<!DOCTYPE html>


<html lang="zh">


<head>
  <meta charset="utf-8" />
    
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
  <title>
    hello-egg |  simplett
  </title>
  <meta name="generator" content="hexo-theme-ayer">
  
  <link rel="shortcut icon" href="/favicon.ico" />
  
  
<link rel="stylesheet" href="/dist/main.css">

  
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/css/remixicon.min.css">

  
<link rel="stylesheet" href="/css/custom.css">

  
  
<script src="https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js"></script>

  
  

  

</head>

</html>

<body>
  <div id="app">
    <main class="content on">
      <section class="outer">
  <article id="post-hello-egg" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h1 class="article-title sea-center" style="border-left:0" itemprop="name">
  hello-egg
</h1>
 

    </header>
    

    
    <div class="article-meta">
      <a href="/2020/04/17/hello-egg/" class="article-date">
  <time datetime="2020-04-17T13:34:39.045Z" itemprop="datePublished">2020-04-17</time>
</a>
      
      
      
<div class="word_count">
    <span class="post-time">
        <span class="post-meta-item-icon">
            <i class="ri-quill-pen-line"></i>
            <span class="post-meta-item-text"> Word count:</span>
            <span class="post-count">12.9k</span>
        </span>
    </span>

    <span class="post-time">
        &nbsp; | &nbsp;
        <span class="post-meta-item-icon">
            <i class="ri-book-open-line"></i>
            <span class="post-meta-item-text"> Reading time≈</span>
            <span class="post-count">60 min</span>
        </span>
    </span>
</div>

      
    </div>
    

    
    
    <div class="tocbot"></div>





    

    
    <div class="article-entry" itemprop="articleBody">
      
      

      
      <h1 id="安装-egg"><a href="#安装-egg" class="headerlink" title="安装 egg"></a>安装 egg</h1><p>我们推荐直接使用脚手架，只需几条简单指令，即可快速生成项目（<code>npm &gt;=6.1.0</code>）:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">mkdir egg-example &amp;&amp; cd egg-example</span><br><span class="line">npm init egg --type&#x3D;simple</span><br><span class="line">npm i</span><br></pre></td></tr></table></figure>

<p>启动项目:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm run dev</span><br><span class="line">open http:&#x2F;&#x2F;localhost:7001</span><br></pre></td></tr></table></figure>

<h1 id="目录结构"><a href="#目录结构" class="headerlink" title="目录结构"></a>目录结构</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">egg-project</span><br><span class="line">├── package.json</span><br><span class="line">├── app.js (可选)</span><br><span class="line">├── agent.js (可选)</span><br><span class="line">├── app（-----------核心------------）</span><br><span class="line">|   ├── router.js（路由）</span><br><span class="line">│   ├── controller（控制器）</span><br><span class="line">│   |   └── home.js</span><br><span class="line">│   ├── service (模型)</span><br><span class="line">│   |   └── user.js</span><br><span class="line">│   ├── middleware (中间件)</span><br><span class="line">│   |   └── response_time.js</span><br><span class="line">│   ├── schedule (可选)</span><br><span class="line">│   |   └── my_task.js</span><br><span class="line">│   ├── public (静态资源)</span><br><span class="line">│   |   └── reset.css</span><br><span class="line">│   ├── view (模板视图)</span><br><span class="line">│   |   └── home.tpl</span><br><span class="line">│   └── extend (扩展)</span><br><span class="line">│       ├── helper.js (可选)</span><br><span class="line">│       ├── request.js (可选)</span><br><span class="line">│       ├── response.js (可选)</span><br><span class="line">│       ├── context.js (可选)</span><br><span class="line">│       ├── application.js (可选)</span><br><span class="line">│       └── agent.js (可选)</span><br><span class="line">├── config</span><br><span class="line">|   ├── plugin.js</span><br><span class="line">|   ├── config.default.js</span><br><span class="line">│   ├── config.prod.js</span><br><span class="line">|   ├── config.test.js (可选)</span><br><span class="line">|   ├── config.local.js (可选)</span><br><span class="line">|   └── config.unittest.js (可选)</span><br><span class="line">└── test</span><br><span class="line">    ├── middleware</span><br><span class="line">    |   └── response_time.test.js</span><br><span class="line">    └── controller</span><br><span class="line">        └── home.test.js</span><br></pre></td></tr></table></figure>

<h1 id="路由相关"><a href="#路由相关" class="headerlink" title="路由相关"></a>路由相关</h1><h2 id="1-get-传值"><a href="#1-get-传值" class="headerlink" title="1. get 传值"></a>1. get 传值</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// router.js</span></span><br><span class="line">router.get(<span class="string">'/admin/:id'</span>, controller.admin.index);</span><br><span class="line"></span><br><span class="line"><span class="comment">// controller</span></span><br><span class="line"><span class="keyword">async</span> index(ctx) &#123;</span><br><span class="line">    <span class="comment">// 获取路由get传值参数（路由:id）</span></span><br><span class="line">    ctx.params;</span><br><span class="line">    <span class="comment">// 获取url的问号get传值参数</span></span><br><span class="line">    ctx.query;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="2-4-种配置方法"><a href="#2-4-种配置方法" class="headerlink" title="2. 4 种配置方法"></a>2. 4 种配置方法</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">router.verb(<span class="string">'path-match'</span>, app.controller.action);</span><br><span class="line">router.verb(<span class="string">'router-name'</span>, <span class="string">'path-match'</span>, app.controller.action);<span class="comment">// 第一个参数可以给name</span></span><br><span class="line">router.verb(<span class="string">'path-match'</span>, middleware1, ..., middlewareN, app.controller.action);</span><br><span class="line">router.verb(<span class="string">'router-name'</span>, <span class="string">'path-match'</span>, middleware1, ..., middlewareN, app.controller.action);</span><br></pre></td></tr></table></figure>

<h1 id="重定向"><a href="#重定向" class="headerlink" title="重定向"></a>重定向</h1><h2 id="1-ctx"><a href="#1-ctx" class="headerlink" title="1. ctx"></a>1. ctx</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> index() &#123;</span><br><span class="line">    <span class="keyword">this</span>.ctx.status = <span class="number">301</span>; <span class="comment">// 把重定向改为301</span></span><br><span class="line">    <span class="keyword">this</span>.ctx.redirect(<span class="string">'/admin/add'</span>); <span class="comment">// 默认临时重定向 302</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="2-路由重定向"><a href="#2-路由重定向" class="headerlink" title="2. 路由重定向"></a>2. 路由重定向</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">app.router.redirect(<span class="string">"/"</span>, <span class="string">"/home/index"</span>, <span class="number">302</span>);</span><br></pre></td></tr></table></figure>

<h2 id="3-路由分组"><a href="#3-路由分组" class="headerlink" title="3.路由分组"></a>3.路由分组</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app/router.js</span></span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function">(<span class="params">app</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">require</span>(<span class="string">"./router/news"</span>)(app);</span><br><span class="line">  <span class="built_in">require</span>(<span class="string">"./router/admin"</span>)(app);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// app/router/news.js</span></span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function">(<span class="params">app</span>) =&gt;</span> &#123;</span><br><span class="line">  app.router.get(<span class="string">"/news/list"</span>, app.controller.news.list);</span><br><span class="line">  app.router.get(<span class="string">"/news/detail"</span>, app.controller.news.detail);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// app/router/admin.js</span></span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function">(<span class="params">app</span>) =&gt;</span> &#123;</span><br><span class="line">  app.router.get(<span class="string">"/admin/user"</span>, app.controller.admin.user);</span><br><span class="line">  app.router.get(<span class="string">"/admin/log"</span>, app.controller.admin.log);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h1 id="控制器"><a href="#控制器" class="headerlink" title="控制器"></a>控制器</h1><h2 id="自定义-Controller-基类"><a href="#自定义-Controller-基类" class="headerlink" title="自定义 Controller 基类"></a>自定义 Controller 基类</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app/core/base_controller.js</span></span><br><span class="line"><span class="keyword">const</span> &#123; Controller &#125; = <span class="built_in">require</span>(<span class="string">"egg"</span>);</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BaseController</span> <span class="keyword">extends</span> <span class="title">Controller</span> </span>&#123;</span><br><span class="line">  <span class="keyword">get</span> user() &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">this</span>.ctx.session.user;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  success(data) &#123;</span><br><span class="line">    <span class="keyword">this</span>.ctx.body = &#123;</span><br><span class="line">      success: <span class="literal">true</span>,</span><br><span class="line">      data,</span><br><span class="line">    &#125;;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  notFound(msg) &#123;</span><br><span class="line">    msg = msg || <span class="string">"not found"</span>;</span><br><span class="line">    <span class="keyword">this</span>.ctx.throw(<span class="number">404</span>, msg);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">module</span>.exports = BaseController;</span><br></pre></td></tr></table></figure>

<p>此时在编写应用的 Controller 时，可以继承 BaseController，直接使用基类上的方法：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//app/controller/post.js</span></span><br><span class="line"><span class="keyword">const</span> Controller = <span class="built_in">require</span>(<span class="string">"../core/base_controller"</span>);</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">PostController</span> <span class="keyword">extends</span> <span class="title">Controller</span> </span>&#123;</span><br><span class="line">  <span class="keyword">async</span> list() &#123;</span><br><span class="line">    <span class="keyword">const</span> posts = <span class="keyword">await</span> <span class="keyword">this</span>.service.listByUser(<span class="keyword">this</span>.user);</span><br><span class="line">    <span class="keyword">this</span>.success(posts);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="模板引擎"><a href="#模板引擎" class="headerlink" title="模板引擎"></a>模板引擎</h1><h2 id="1-安装和使用-ejs"><a href="#1-安装和使用-ejs" class="headerlink" title="1. 安装和使用 ejs"></a>1. 安装和使用 ejs</h2><h3 id="（1）安装："><a href="#（1）安装：" class="headerlink" title="（1）安装："></a>（1）安装：</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i egg-view-ejs --save</span><br></pre></td></tr></table></figure>

<h3 id="（2）配置：-config"><a href="#（2）配置：-config" class="headerlink" title="（2）配置：/config"></a>（2）配置：/config</h3><p>config/config.default.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="params">appInfo</span> =&gt;</span> &#123;</span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    config.view = &#123;</span><br><span class="line">        mapping: &#123;</span><br><span class="line">            <span class="string">'.html'</span>: <span class="string">'ejs'</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">	...</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>config/plugin.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="comment">// 配置ejs</span></span><br><span class="line">  ejs: &#123;</span><br><span class="line">    enable: <span class="literal">true</span>,</span><br><span class="line">    package: <span class="string">"egg-view-ejs"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h3 id="（3）使用"><a href="#（3）使用" class="headerlink" title="（3）使用"></a>（3）使用</h3><p>app/controller</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> index() &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; ctx &#125; = <span class="keyword">this</span>;</span><br><span class="line">    <span class="comment">// 渲染变量</span></span><br><span class="line">    <span class="keyword">let</span> msg = <span class="string">"测试内容"</span>;</span><br><span class="line">    <span class="keyword">let</span> list = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>];</span><br><span class="line">    <span class="comment">// 渲染模板（render需要加await）</span></span><br><span class="line">    <span class="keyword">await</span> ctx.render(<span class="string">'index'</span>, &#123;</span><br><span class="line">        msg,</span><br><span class="line">        list</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>app/view/index.html</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="meta-keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"width=device-width, initial-scale=1.0"</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">"X-UA-Compatible"</span> <span class="attr">content</span>=<span class="string">"ie=edge"</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>Document<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--渲染变量--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">%=msg%</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">      &lt;% for(var i=0; i &lt; list.length; i++)&#123; %&gt;</span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">%=list[i]%</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">%</span> &#125; %&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--加载 app/public 下的资源文件--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">"/public/images/find.png"</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h1 id="服务（模型）"><a href="#服务（模型）" class="headerlink" title="服务（模型）"></a>服务（模型）</h1><p>控制器调用 <code>home</code> 模型的 <code>ceshi</code> 方法</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">await</span> <span class="keyword">this</span>.service.home.ceshi();</span><br></pre></td></tr></table></figure>

<p>模型之间相互调用（同上）</p>
<h1 id="模型和数据库"><a href="#模型和数据库" class="headerlink" title="模型和数据库"></a>模型和数据库</h1><h2 id="配置和创建迁移文件"><a href="#配置和创建迁移文件" class="headerlink" title="配置和创建迁移文件"></a>配置和创建迁移文件</h2><h3 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h3><ol>
<li>安装并配置<a href="https://github.com/eggjs/egg-sequelize" target="_blank" rel="noopener">egg-sequelize</a>插件（它会辅助我们将定义好的 Model 对象加载到 app 和 ctx 上）和<a href="https://github.com/sidorares/node-mysql2" target="_blank" rel="noopener">mysql2</a>模块：</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install --save egg-sequelize mysql2</span><br></pre></td></tr></table></figure>

<ol start="2">
<li>在<code>config/plugin.js</code>中引入 egg-sequelize 插件</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">exports.sequelize &#x3D; &#123;</span><br><span class="line">  enable: true,</span><br><span class="line">  package: &#39;egg-sequelize&#39;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<ol start="3">
<li>在<code>config/config.default.js</code></li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">config.sequelize = &#123;</span><br><span class="line">  dialect: <span class="string">"mysql"</span>,</span><br><span class="line">  host: <span class="string">"127.0.0.1"</span>,</span><br><span class="line">  username: <span class="string">"root"</span>,</span><br><span class="line">  password: <span class="string">"root"</span>,</span><br><span class="line">  port: <span class="number">3306</span>,</span><br><span class="line">  database: <span class="string">"friends"</span>,</span><br><span class="line">  <span class="comment">// 中国时区</span></span><br><span class="line">  timezone: <span class="string">"+08:00"</span>,</span><br><span class="line">  define: &#123;</span><br><span class="line">    <span class="comment">// 取消数据表名复数</span></span><br><span class="line">    freezeTableName: <span class="literal">true</span>,</span><br><span class="line">    <span class="comment">// 自动写入时间戳 created_at updated_at</span></span><br><span class="line">    timestamps: <span class="literal">true</span>,</span><br><span class="line">    <span class="comment">// 字段生成软删除时间戳 deleted_at</span></span><br><span class="line">    paranoid: <span class="literal">true</span>,</span><br><span class="line">    createdAt: <span class="string">"created_at"</span>,</span><br><span class="line">    updatedAt: <span class="string">"updated_at"</span>,</span><br><span class="line">    deletedAt: <span class="string">"deleted_at"</span>,</span><br><span class="line">    <span class="comment">// 所有驼峰命名格式化</span></span><br><span class="line">    underscored: <span class="literal">true</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<ol start="4">
<li>sequelize 提供了<a href="https://github.com/sequelize/cli" target="_blank" rel="noopener">sequelize-cli</a>工具来实现<a href="http://docs.sequelizejs.com/manual/tutorial/migrations.html" target="_blank" rel="noopener">Migrations</a>，我们也可以在 egg 项目中引入 sequelize-cli。</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install --save-dev sequelize-cli</span><br></pre></td></tr></table></figure>

<ol start="5">
<li>egg 项目中，我们希望将所有数据库 Migrations 相关的内容都放在<code>database</code>目录下，所以我们在项目根目录下新建一个<code>.sequelizerc</code>配置文件：</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">"use strict"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">"path"</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  config: path.join(__dirname, <span class="string">"database/config.json"</span>),</span><br><span class="line">  <span class="string">"migrations-path"</span>: path.join(__dirname, <span class="string">"database/migrations"</span>),</span><br><span class="line">  <span class="string">"seeders-path"</span>: path.join(__dirname, <span class="string">"database/seeders"</span>),</span><br><span class="line">  <span class="string">"models-path"</span>: path.join(__dirname, <span class="string">"app/model"</span>),</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<ol start="6">
<li>初始化 Migrations 配置文件和目录</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">npx sequelize init:config</span><br><span class="line">npx sequelize init:migrations</span><br><span class="line"><span class="comment">// npx sequelize init:models</span></span><br></pre></td></tr></table></figure>

<ol start="7">
<li>行完后会生成<code>database/config.json</code>文件和<code>database/migrations</code>目录，我们修改一下<code>database/config.json</code>中的内容，将其改成我们项目中使用的数据库配置：</li>
</ol>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"development"</span>: &#123;</span><br><span class="line">    <span class="attr">"username"</span>: <span class="string">"root"</span>,</span><br><span class="line">    <span class="attr">"password"</span>: <span class="literal">null</span>,</span><br><span class="line">    <span class="attr">"database"</span>: <span class="string">"test"</span>,</span><br><span class="line">    <span class="attr">"host"</span>: <span class="string">"127.0.0.1"</span>,</span><br><span class="line">    <span class="attr">"dialect"</span>: <span class="string">"mysql"</span>,</span><br><span class="line">    <span class="attr">"timezone"</span>: <span class="string">"+08:00"</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ol start="8">
<li>创建数据库</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx sequelize db:create</span><br></pre></td></tr></table></figure>

<h3 id="创建数据迁移表"><a href="#创建数据迁移表" class="headerlink" title="创建数据迁移表"></a>创建数据迁移表</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx sequelize migration:generate --name=init-users</span><br></pre></td></tr></table></figure>

<p>1.执行完命令后，会在 database / migrations / 目录下生成数据表迁移文件，然后定义</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">"use strict"</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  up: <span class="keyword">async</span> (queryInterface, Sequelize) =&gt; &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; INTEGER, STRING, DATE, ENUM &#125; = Sequelize;</span><br><span class="line">    <span class="comment">// 创建表</span></span><br><span class="line">    <span class="keyword">await</span> queryInterface.createTable(</span><br><span class="line">      <span class="string">"users"</span>,</span><br><span class="line">      &#123;</span><br><span class="line">        id: &#123;</span><br><span class="line">          type: INTEGER(<span class="number">20</span>).UNSIGNED,</span><br><span class="line">          primaryKey: <span class="literal">true</span>,</span><br><span class="line">          autoIncrement: <span class="literal">true</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        username: &#123;</span><br><span class="line">          type: STRING(<span class="number">30</span>),</span><br><span class="line">          allowNull: <span class="literal">false</span>,</span><br><span class="line">          defaultValue: <span class="string">""</span>,</span><br><span class="line">          comment: <span class="string">"用户名称"</span>,</span><br><span class="line">          unique: <span class="literal">true</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        email: &#123;</span><br><span class="line">          type: STRING(<span class="number">160</span>),</span><br><span class="line">          allowNull: <span class="literal">false</span>,</span><br><span class="line">          defaultValue: <span class="string">""</span>,</span><br><span class="line">          comment: <span class="string">"用户邮箱"</span>,</span><br><span class="line">          unique: <span class="literal">true</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        password: &#123; <span class="attr">type</span>: STRING(<span class="number">200</span>), <span class="attr">allowNull</span>: <span class="literal">false</span>, <span class="attr">defaultValue</span>: <span class="string">""</span> &#125;,</span><br><span class="line">        avatar_url: &#123; <span class="attr">type</span>: STRING(<span class="number">200</span>), <span class="attr">allowNull</span>: <span class="literal">true</span>, <span class="attr">defaultValue</span>: <span class="string">""</span> &#125;,</span><br><span class="line">        mobile: &#123;</span><br><span class="line">          type: STRING(<span class="number">20</span>),</span><br><span class="line">          allowNull: <span class="literal">false</span>,</span><br><span class="line">          defaultValue: <span class="string">""</span>,</span><br><span class="line">          comment: <span class="string">"用户手机"</span>,</span><br><span class="line">          unique: <span class="literal">true</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        prifix: &#123; <span class="attr">type</span>: STRING(<span class="number">32</span>), <span class="attr">allowNull</span>: <span class="literal">false</span>, <span class="attr">defaultValue</span>: <span class="string">""</span> &#125;,</span><br><span class="line">        abstract: &#123; <span class="attr">type</span>: STRING(<span class="number">255</span>), <span class="attr">allowNull</span>: <span class="literal">true</span>, <span class="attr">defaultValue</span>: <span class="string">""</span> &#125;,</span><br><span class="line">        role_id: &#123;</span><br><span class="line">          type: INTEGER,</span><br><span class="line">          <span class="comment">//  定义外键（重要）</span></span><br><span class="line">          references: &#123;</span><br><span class="line">            model: <span class="string">"users"</span>, <span class="comment">// 对应表名称（数据表名称）</span></span><br><span class="line">            key: <span class="string">"id"</span>, <span class="comment">// 对应表的主键</span></span><br><span class="line">          &#125;,</span><br><span class="line">          onUpdate: <span class="string">"restrict"</span>, <span class="comment">// 更新时操作</span></span><br><span class="line">          onDelete: <span class="string">"cascade"</span>, <span class="comment">// 删除时操作</span></span><br><span class="line">        &#125;,</span><br><span class="line">        gender: &#123;</span><br><span class="line">          type: ENUM,</span><br><span class="line">          values: [<span class="string">"男"</span>, <span class="string">"女"</span>, <span class="string">"保密"</span>],</span><br><span class="line">          allowNull: <span class="literal">true</span>,</span><br><span class="line">          defaultValue: <span class="string">"男"</span>,</span><br><span class="line">          comment: <span class="string">"用户性别"</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        created_at: DATE,</span><br><span class="line">        updated_at: DATE,</span><br><span class="line">      &#125;,</span><br><span class="line">      &#123; <span class="attr">engine</span>: <span class="string">"MYISAM"</span> &#125;</span><br><span class="line">    );</span><br><span class="line">    <span class="comment">// 添加索引</span></span><br><span class="line">    queryInterface.addIndex(<span class="string">"users"</span>, [<span class="string">"gender"</span>]);</span><br><span class="line">    <span class="comment">// 添加唯一索引</span></span><br><span class="line">    queryInterface.addIndex(<span class="string">"users"</span>, &#123;</span><br><span class="line">      name: <span class="string">"name"</span>, <span class="comment">// 索引名称</span></span><br><span class="line">      unique: <span class="literal">true</span>, <span class="comment">// 唯一索引</span></span><br><span class="line">      fields: [<span class="string">"name"</span>], <span class="comment">// 索引对应字段</span></span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  down: <span class="keyword">async</span> (queryInterface) =&gt; &#123;</span><br><span class="line">    <span class="keyword">await</span> queryInterface.dropTable(<span class="string">"users"</span>);</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<ul>
<li>执行 migrate 进行数据库变更</li>
</ul>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 升级数据库</span></span><br><span class="line">npx sequelize db:migrate</span><br><span class="line"><span class="comment"># 如果有问题需要回滚，可以通过 `db:migrate:undo` 回退一个变更</span></span><br><span class="line"><span class="comment"># npx sequelize db:migrate:undo</span></span><br><span class="line"><span class="comment"># 可以通过 `db:migrate:undo:all` 回退到初始状态</span></span><br><span class="line"><span class="comment"># npx sequelize db:migrate:undo:all</span></span><br></pre></td></tr></table></figure>

<h3 id="已创建新增字段"><a href="#已创建新增字段" class="headerlink" title="已创建新增字段"></a>已创建新增字段</h3><p>1.创建迁移文件：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx sequelize migration:generate --name&#x3D;user-addcolumn</span><br></pre></td></tr></table></figure>

<p>2.执行完命令后，会在 database / migrations / 目录下生成数据表迁移文件，然后定义</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">"use strict"</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  up: <span class="function">(<span class="params">queryInterface, Sequelize</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> queryInterface.sequelize.transaction(<span class="function">(<span class="params">t</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">Promise</span>.all([</span><br><span class="line">        queryInterface.addColumn(</span><br><span class="line">          <span class="string">"user"</span>,</span><br><span class="line">          <span class="string">"role_id"</span>,</span><br><span class="line">          &#123;</span><br><span class="line">            type: Sequelize.INTEGER,</span><br><span class="line">          &#125;,</span><br><span class="line">          &#123; <span class="attr">transaction</span>: t &#125;</span><br><span class="line">        ),</span><br><span class="line">        queryInterface.addColumn(</span><br><span class="line">          <span class="string">"user"</span>,</span><br><span class="line">          <span class="string">"ceshi"</span>,</span><br><span class="line">          &#123;</span><br><span class="line">            type: Sequelize.STRING,</span><br><span class="line">          &#125;,</span><br><span class="line">          &#123; <span class="attr">transaction</span>: t &#125;</span><br><span class="line">        ),</span><br><span class="line">      ]);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  down: <span class="function">(<span class="params">queryInterface, Sequelize</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> queryInterface.sequelize.transaction(<span class="function">(<span class="params">t</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">Promise</span>.all([</span><br><span class="line">        queryInterface.removeColumn(<span class="string">"user"</span>, <span class="string">"role_id"</span>, &#123; <span class="attr">transaction</span>: t &#125;),</span><br><span class="line">        queryInterface.removeColumn(<span class="string">"user"</span>, <span class="string">"ceshi"</span>, &#123; <span class="attr">transaction</span>: t &#125;),</span><br><span class="line">      ]);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>3.执行 migrate 进行数据库变更</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx sequelize db:migrate</span><br></pre></td></tr></table></figure>

<h3 id="创建模型"><a href="#创建模型" class="headerlink" title="创建模型"></a>创建模型</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app / model / user.js</span></span><br><span class="line"></span><br><span class="line"><span class="meta">"use strict"</span>;</span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function">(<span class="params">app</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> &#123; STRING, INTEGER, DATE &#125; = app.Sequelize;</span><br><span class="line">  <span class="comment">// 配置（重要：一定要配置详细，一定要！！！）</span></span><br><span class="line">  <span class="keyword">const</span> User = app.model.define(</span><br><span class="line">    <span class="string">"user"</span>,</span><br><span class="line">    &#123;</span><br><span class="line">      id: &#123; <span class="attr">type</span>: INTEGER, <span class="attr">primaryKey</span>: <span class="literal">true</span>, <span class="attr">autoIncrement</span>: <span class="literal">true</span> &#125;,</span><br><span class="line">      name: STRING(<span class="number">30</span>),</span><br><span class="line">      age: INTEGER,</span><br><span class="line">      created_at: DATE,</span><br><span class="line">      updated_at: DATE,</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      timestamps: <span class="literal">true</span>, <span class="comment">// 是否自动写入时间戳</span></span><br><span class="line">      tableName: <span class="string">"users"</span>, <span class="comment">// 自定义数据表名称</span></span><br><span class="line">    &#125;</span><br><span class="line">  );</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> User;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>这个 Model 就可以在 Controller 和 Service 中通过 <code>app.model.User</code> 或者 <code>ctx.model.User</code> 访问到了，例如我们编写 <code>app/controller/users.js</code>：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app/controller/users.js</span></span><br><span class="line"><span class="keyword">const</span> Controller = <span class="built_in">require</span>(<span class="string">"egg"</span>).Controller;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">toInt</span>(<span class="params">str</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> str === <span class="string">"number"</span>) <span class="keyword">return</span> str;</span><br><span class="line">  <span class="keyword">if</span> (!str) <span class="keyword">return</span> str;</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">parseInt</span>(str, <span class="number">10</span>) || <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UserController</span> <span class="keyword">extends</span> <span class="title">Controller</span> </span>&#123;</span><br><span class="line">  <span class="keyword">async</span> index() &#123;</span><br><span class="line">    <span class="keyword">const</span> ctx = <span class="keyword">this</span>.ctx;</span><br><span class="line">    <span class="keyword">const</span> query = &#123;</span><br><span class="line">      limit: toInt(ctx.query.limit),</span><br><span class="line">      offset: toInt(ctx.query.offset),</span><br><span class="line">    &#125;;</span><br><span class="line">    ctx.body = <span class="keyword">await</span> ctx.model.User.findAll(query);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> show() &#123;</span><br><span class="line">    <span class="keyword">const</span> ctx = <span class="keyword">this</span>.ctx;</span><br><span class="line">    ctx.body = <span class="keyword">await</span> ctx.model.User.findByPk(toInt(ctx.params.id));</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> create() &#123;</span><br><span class="line">    <span class="keyword">const</span> ctx = <span class="keyword">this</span>.ctx;</span><br><span class="line">    <span class="keyword">const</span> &#123; name, age &#125; = ctx.request.body;</span><br><span class="line">    <span class="keyword">const</span> user = <span class="keyword">await</span> ctx.model.User.create(&#123; name, age &#125;);</span><br><span class="line">    ctx.status = <span class="number">201</span>;</span><br><span class="line">    ctx.body = user;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> update() &#123;</span><br><span class="line">    <span class="keyword">const</span> ctx = <span class="keyword">this</span>.ctx;</span><br><span class="line">    <span class="keyword">const</span> id = toInt(ctx.params.id);</span><br><span class="line">    <span class="keyword">const</span> user = <span class="keyword">await</span> ctx.model.User.findByPk(id);</span><br><span class="line">    <span class="keyword">if</span> (!user) &#123;</span><br><span class="line">      ctx.status = <span class="number">404</span>;</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> &#123; name, age &#125; = ctx.request.body;</span><br><span class="line">    <span class="keyword">await</span> user.update(&#123; name, age &#125;);</span><br><span class="line">    ctx.body = user;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> destroy() &#123;</span><br><span class="line">    <span class="keyword">const</span> ctx = <span class="keyword">this</span>.ctx;</span><br><span class="line">    <span class="keyword">const</span> id = toInt(ctx.params.id);</span><br><span class="line">    <span class="keyword">const</span> user = <span class="keyword">await</span> ctx.model.User.findByPk(id);</span><br><span class="line">    <span class="keyword">if</span> (!user) &#123;</span><br><span class="line">      ctx.status = <span class="number">404</span>;</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">await</span> user.destroy();</span><br><span class="line">    ctx.status = <span class="number">200</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = UserController;</span><br></pre></td></tr></table></figure>

<p>最后我们将这个 controller 挂载到路由上：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app/router.js</span></span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function">(<span class="params">app</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> &#123; router, controller &#125; = app;</span><br><span class="line">  router.resources(<span class="string">"users"</span>, <span class="string">"/users"</span>, controller.users);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>针对 <code>users</code> 表的 CURD 操作的接口就开发完了</p>
<h3 id="模型其他参数"><a href="#模型其他参数" class="headerlink" title="模型其他参数"></a>模型其他参数</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 配置（重要）</span></span><br><span class="line"><span class="keyword">const</span> User = app.model.define(</span><br><span class="line">  <span class="string">"user"</span>,</span><br><span class="line">  &#123;</span><br><span class="line">    id: &#123; <span class="attr">type</span>: INTEGER, <span class="attr">primaryKey</span>: <span class="literal">true</span>, <span class="attr">autoIncrement</span>: <span class="literal">true</span> &#125;,</span><br><span class="line">    name: STRING(<span class="number">30</span>),</span><br><span class="line">    age: INTEGER,</span><br><span class="line">    created_at: DATE,</span><br><span class="line">    updated_at: DATE,</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="comment">// 自定义表名</span></span><br><span class="line">    freezeTableName: <span class="literal">true</span>,</span><br><span class="line">    tableName: <span class="string">"xyz_users"</span>,</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 是否需要增加createdAt、updatedAt、deletedAt字段</span></span><br><span class="line">    timestamps: <span class="literal">true</span>,</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 不需要createdAt字段</span></span><br><span class="line">    createdAt: <span class="literal">false</span>,</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 将updatedAt字段改个名</span></span><br><span class="line">    updatedAt: <span class="string">"utime"</span>,</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 将deletedAt字段改名</span></span><br><span class="line">    <span class="comment">// 同时需要设置paranoid为true（此种模式下，删除数据时不会进行物理删除，而是设置deletedAt为当前时间</span></span><br><span class="line">    deletedAt: <span class="string">"dtime"</span>,</span><br><span class="line">    paranoid: <span class="literal">true</span>,</span><br><span class="line">  &#125;</span><br><span class="line">);</span><br></pre></td></tr></table></figure>

<h3 id="sequelize-命令"><a href="#sequelize-命令" class="headerlink" title="sequelize 命令"></a>sequelize 命令</h3><table>
<thead>
<tr>
<th align="left">命令</th>
<th align="left">含义</th>
</tr>
</thead>
<tbody><tr>
<td align="left">sequelize db:migrate</td>
<td align="left">运行迁移文件</td>
</tr>
<tr>
<td align="left">sequelize db:migrate:status</td>
<td align="left">列出所有迁移的状态</td>
</tr>
<tr>
<td align="left">sequelize db:migrate:undo</td>
<td align="left">隔离数据库：迁移：撤消</td>
</tr>
<tr>
<td align="left">sequelize db:migrate:undo:all</td>
<td align="left">还原所有运行的迁移</td>
</tr>
<tr>
<td align="left">sequelize db:create</td>
<td align="left">创建由配置指定的数据库</td>
</tr>
<tr>
<td align="left">sequelize db:drop</td>
<td align="left">删除由配置指定的数据库</td>
</tr>
</tbody></table>
<h3 id="外键约束（重要）"><a href="#外键约束（重要）" class="headerlink" title="外键约束（重要）"></a>外键约束（重要）</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 迁移文件</span></span><br><span class="line">queryInterface.addConstraint(<span class="string">"tableName"</span>, [<span class="string">"user_id"</span>], &#123;</span><br><span class="line">  type: <span class="string">"foreign key"</span>,</span><br><span class="line">  name: <span class="string">"user_id"</span>,</span><br><span class="line">  references: &#123;</span><br><span class="line">    <span class="comment">//Required field</span></span><br><span class="line">    table: <span class="string">"users"</span>,</span><br><span class="line">    field: <span class="string">"id"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  onDelete: <span class="string">"cascade"</span>,</span><br><span class="line">  onUpdate: <span class="string">"cascade"</span>,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="创建第一个种子"><a href="#创建第一个种子" class="headerlink" title="创建第一个种子"></a>创建第一个种子</h3><p>假设我们希望在默认情况下将一些数据插入到几个表中. 如果我们跟进前面的例子,我们可以考虑为 <code>User</code> 表创建演示用户.</p>
<p>要管理所有数据迁移,你可以使用 <code>seeders</code>. 种子文件是数据的一些变化,可用于使用样本数据或测试数据填充数据库表.</p>
<p>让我们创建一个种子文件,它会将一个演示用户添加到我们的 <code>User</code> 表中.</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx sequelize seed:generate --name demo-user</span><br></pre></td></tr></table></figure>

<p>这个命令将会在 <code>seeders</code> 文件夹中创建一个种子文件.文件名看起来像是 <code>XXXXXXXXXXXXXX-demo-user.js</code>,它遵循相同的 <code>up/down</code> 语义,如迁移文件.</p>
<p>现在我们应该编辑这个文件,将演示用户插入<code>User</code>表.</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">"use strict"</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  up: <span class="function">(<span class="params">queryInterface, Sequelize</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> queryInterface.bulkInsert(</span><br><span class="line">      <span class="string">"Users"</span>,</span><br><span class="line">      [</span><br><span class="line">        &#123;</span><br><span class="line">          firstName: <span class="string">"John"</span>,</span><br><span class="line">          lastName: <span class="string">"Doe"</span>,</span><br><span class="line">          email: <span class="string">"demo@demo.com"</span>,</span><br><span class="line">          createdAt: <span class="keyword">new</span> <span class="built_in">Date</span>(),</span><br><span class="line">          updatedAt: <span class="keyword">new</span> <span class="built_in">Date</span>(),</span><br><span class="line">        &#125;,</span><br><span class="line">      ],</span><br><span class="line">      &#123;&#125;</span><br><span class="line">    );</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  down: <span class="function">(<span class="params">queryInterface, Sequelize</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> queryInterface.bulkDelete(<span class="string">"Users"</span>, <span class="literal">null</span>, &#123;&#125;);</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h3 id="运行种子"><a href="#运行种子" class="headerlink" title="运行种子"></a>运行种子</h3><p>在上一步中,你创建了一个种子文件. 但它还没有保存到数据库. 为此,我们需要运行一个简单的命令.</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx sequelize db:seed:all</span><br></pre></td></tr></table></figure>

<p>这将执行该种子文件,你将有一个演示用户插入 <code>User</code> 表.</p>
<p><strong>注意:</strong> _ <code>seeders</code> 执行不会存储在任何使用 <code>SequelizeMeta</code> 表的迁移的地方. 如果你想覆盖这个,请阅读 <code>存储</code> 部分_</p>
<h3 id="撤销种子"><a href="#撤销种子" class="headerlink" title="撤销种子"></a>撤销种子</h3><p>Seeders 如果使用了任何存储那么就可以被撤消. 有两个可用的命令</p>
<p>如果你想撤消最近的种子</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx sequelize db:seed:undo</span><br></pre></td></tr></table></figure>

<p>如果你想撤消特定的种子</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx sequelize db:seed:undo --seed name-of-seed-as-in-data</span><br></pre></td></tr></table></figure>

<p>如果你想撤消所有的种子</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx sequelize db:seed:undo:all</span><br></pre></td></tr></table></figure>

<h2 id="关联操作"><a href="#关联操作" class="headerlink" title="关联操作"></a>关联操作</h2><h3 id="一对一"><a href="#一对一" class="headerlink" title="一对一"></a>一对一</h3><p>模型层：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 一个用户对应一个用户资料</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// app/model/user.js</span></span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function">(<span class="params">app</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> &#123; STRING, INTEGER, DATE &#125; = app.Sequelize;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> User = app.model.define(<span class="string">"user"</span>, &#123;</span><br><span class="line">    id: &#123; <span class="attr">type</span>: INTEGER, <span class="attr">primaryKey</span>: <span class="literal">true</span>, <span class="attr">autoIncrement</span>: <span class="literal">true</span> &#125;,</span><br><span class="line">    name: STRING(<span class="number">30</span>),</span><br><span class="line">    age: INTEGER,</span><br><span class="line">    created_at: DATE,</span><br><span class="line">    updated_at: DATE,</span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="comment">// 关联关系</span></span><br><span class="line">  User.associate = <span class="function"><span class="keyword">function</span> (<span class="params">models</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 关联用户资料 一对一</span></span><br><span class="line">    User.hasOne(app.model.Userinfo);</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">return</span> User;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// app/model/userinfo.js</span></span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function">(<span class="params">app</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> &#123; STRING, INTEGER, DATE &#125; = app.Sequelize;</span><br><span class="line">  <span class="keyword">const</span> userinfo = app.model.define(</span><br><span class="line">    <span class="string">"userinfo"</span>,</span><br><span class="line">    &#123;</span><br><span class="line">      nickname: STRING,</span><br><span class="line">      user_id: INTEGER,</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;&#125;</span><br><span class="line">  );</span><br><span class="line">  <span class="comment">// 关联用户表</span></span><br><span class="line">  userinfo.associate = <span class="function"><span class="keyword">function</span> (<span class="params">models</span>) </span>&#123;</span><br><span class="line">    app.model.Userinfo.belongsTo(app.model.User);</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">return</span> userinfo;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>控制器调用：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app/controller/users.js</span></span><br><span class="line"><span class="comment">// 显示单条</span></span><br><span class="line"><span class="keyword">async</span> show() &#123;</span><br><span class="line">    <span class="comment">// 根据主键查询 查询一条用findOne</span></span><br><span class="line">    <span class="keyword">this</span>.ctx.body = <span class="keyword">await</span> <span class="keyword">this</span>.ctx.model.User.findOne(&#123;</span><br><span class="line">        <span class="comment">// 主表查询字段限制</span></span><br><span class="line">        attributes:[<span class="string">'name'</span>],</span><br><span class="line">        <span class="comment">// 关联查询</span></span><br><span class="line">        include: [&#123;</span><br><span class="line">            <span class="comment">// 需要查询的模型</span></span><br><span class="line">            model: <span class="keyword">this</span>.app.model.Userinfo,</span><br><span class="line">            <span class="comment">// 副表查询的字段</span></span><br><span class="line">            attributes: [<span class="string">'nickname'</span>]</span><br><span class="line">        &#125;],</span><br><span class="line">        <span class="comment">// 主表条件</span></span><br><span class="line">        where: &#123;</span><br><span class="line">            id: <span class="number">3</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="一对多"><a href="#一对多" class="headerlink" title="一对多"></a>一对多</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">City</span> <span class="keyword">extends</span> <span class="title">Model</span> </span>&#123;&#125;</span><br><span class="line">City.init(&#123; <span class="attr">countryCode</span>: Sequelize.STRING &#125;, &#123; sequelize, <span class="attr">modelName</span>: <span class="string">"city"</span> &#125;);</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Country</span> <span class="keyword">extends</span> <span class="title">Model</span> </span>&#123;&#125;</span><br><span class="line">Country.init(</span><br><span class="line">  &#123; <span class="attr">isoCode</span>: Sequelize.STRING &#125;,</span><br><span class="line">  &#123; sequelize, <span class="attr">modelName</span>: <span class="string">"country"</span> &#125;</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 在这里,我们可以根据国家代码连接国家和城市</span></span><br><span class="line">Country.hasMany(City, &#123; <span class="attr">foreignKey</span>: <span class="string">"countryCode"</span>, <span class="attr">sourceKey</span>: <span class="string">"isoCode"</span> &#125;);</span><br><span class="line">City.belongsTo(Country, &#123; <span class="attr">foreignKey</span>: <span class="string">"countryCode"</span>, <span class="attr">targetKey</span>: <span class="string">"isoCode"</span> &#125;);</span><br></pre></td></tr></table></figure>

<h3 id="多对多"><a href="#多对多" class="headerlink" title="多对多"></a>多对多</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">User.belongsToMany(Project, &#123;</span><br><span class="line">  <span class="keyword">as</span>: <span class="string">"Tasks"</span>,</span><br><span class="line">  through: <span class="string">"worker_tasks"</span>,</span><br><span class="line">  foreignKey: <span class="string">"userId"</span>,</span><br><span class="line">&#125;);</span><br><span class="line">Project.belongsToMany(User, &#123;</span><br><span class="line">  <span class="keyword">as</span>: <span class="string">"Workers"</span>,</span><br><span class="line">  through: <span class="string">"worker_tasks"</span>,</span><br><span class="line">  foreignKey: <span class="string">"projectId"</span>,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="关联常用操作"><a href="#关联常用操作" class="headerlink" title="关联常用操作"></a>关联常用操作</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取关联模型对象，n对一不需要加s</span></span><br><span class="line"><span class="keyword">let</span> userinfo = <span class="keyword">await</span> user.getUserinfo();</span><br><span class="line"><span class="comment">// n对多需要加s</span></span><br><span class="line"><span class="keyword">await</span> user.getPosts(&#123;</span><br><span class="line">  attributes: [<span class="string">"title"</span>],</span><br><span class="line">  where: &#123;</span><br><span class="line">    id: <span class="number">3</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// 关联操作</span></span><br><span class="line"><span class="comment">// 1：用户创建文章（一对多）</span></span><br><span class="line"><span class="keyword">await</span> <span class="keyword">this</span>.ctx.model.Post.create(&#123;</span><br><span class="line">  title: <span class="string">"第一篇文章"</span>,</span><br><span class="line">  user_id: user.id,</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 2.获取当前用户所有文章</span></span><br><span class="line"><span class="keyword">await</span> user.getPosts();</span><br><span class="line"><span class="keyword">await</span> user.getPosts(&#123;</span><br><span class="line">  attributes: [<span class="string">"id"</span>],</span><br><span class="line">  where: &#123;</span><br><span class="line">    title: <span class="string">"测试"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 3：用户删除文章（一对多）</span></span><br><span class="line"><span class="comment">// (1) 获取当前用户的所有文章</span></span><br><span class="line"><span class="keyword">let</span> posts = <span class="keyword">await</span> user.getPosts(&#123;</span><br><span class="line">  attributes: [<span class="string">"id"</span>],</span><br><span class="line">&#125;);</span><br><span class="line">posts = posts.map(<span class="function">(<span class="params">v</span>) =&gt;</span> v.id);</span><br><span class="line"><span class="keyword">await</span> <span class="keyword">this</span>.ctx.model.Post.destroy(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    id: posts,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 场景三：用户关注话题（多对多）</span></span><br><span class="line"><span class="keyword">await</span> <span class="keyword">this</span>.ctx.model.TopicUser.bulkCreate([</span><br><span class="line">  &#123;</span><br><span class="line">    user_id: user.id,</span><br><span class="line">    topic_id: <span class="number">1</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    user_id: user.id,</span><br><span class="line">    topic_id: <span class="number">2</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">]);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 用户关注话题（多对多）</span></span><br><span class="line"><span class="keyword">await</span> <span class="keyword">this</span>.ctx.model.TopicUser.destroy(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    user_id: user.id,</span><br><span class="line">    topic_id: [<span class="number">1</span>, <span class="number">2</span>],</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h2 id="获取器和修改器"><a href="#获取器和修改器" class="headerlink" title="获取器和修改器"></a>获取器和修改器</h2><p>模型层</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app/model/user.js</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function">(<span class="params">app</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> &#123; STRING, INTEGER, DATE &#125; = app.Sequelize;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> User = app.model.define(<span class="string">"user"</span>, &#123;</span><br><span class="line">    id: &#123; <span class="attr">type</span>: INTEGER, <span class="attr">primaryKey</span>: <span class="literal">true</span>, <span class="attr">autoIncrement</span>: <span class="literal">true</span> &#125;,</span><br><span class="line">    name: &#123;</span><br><span class="line">      type: STRING(<span class="number">30</span>),</span><br><span class="line">      <span class="comment">// 单独字段的getter，查询时都会调用</span></span><br><span class="line">      <span class="comment">// this.getDataValue('name') 获取原始值</span></span><br><span class="line">      <span class="keyword">get</span>() &#123;</span><br><span class="line">        <span class="keyword">const</span> age = <span class="keyword">this</span>.getDataValue(<span class="string">"age"</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.getDataValue(<span class="string">"name"</span>) + <span class="string">"年龄："</span> + age;</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">    age: &#123;</span><br><span class="line">      type: INTEGER,</span><br><span class="line">      <span class="comment">// 单独字段的setter，新增和更新时调用</span></span><br><span class="line">      <span class="comment">// this.setDataValue('name') 设置原始值</span></span><br><span class="line">      <span class="keyword">set</span>(val) &#123;</span><br><span class="line">        <span class="keyword">this</span>.setDataValue(<span class="string">"age"</span>, val * <span class="number">10</span>);</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">    created_at: DATE,</span><br><span class="line">    updated_at: DATE,</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 关联用户资料</span></span><br><span class="line">  User.associate = <span class="function"><span class="keyword">function</span> (<span class="params">models</span>) </span>&#123;</span><br><span class="line">    app.model.User.hasOne(app.model.Userinfo);</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">return</span> User;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>控制器层</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> show() &#123;</span><br><span class="line">    <span class="comment">// 根据主键查询</span></span><br><span class="line">    <span class="keyword">let</span> user = <span class="keyword">await</span> <span class="keyword">this</span>.ctx.model.User.findOne(&#123;</span><br><span class="line">        where: &#123;</span><br><span class="line">            id: <span class="number">3</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="comment">// 获取原始值 user.getDataValue('name')</span></span><br><span class="line">    <span class="keyword">this</span>.ctx.body = user.getDataValue(<span class="string">'name'</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="模型钩子"><a href="#模型钩子" class="headerlink" title="模型钩子"></a>模型钩子</h2><p>模型层</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="params">app</span> =&gt;</span> &#123;</span><br><span class="line"></span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 钩子</span></span><br><span class="line">    <span class="comment">// 查询前</span></span><br><span class="line">    User.beforeFind(<span class="function">(<span class="params">user, option</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'查询前'</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="comment">// 查询后</span></span><br><span class="line">    User.afterFind(<span class="function">(<span class="params">user, option</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'查询后'</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="comment">// 新增前</span></span><br><span class="line">    User.beforeCreate(<span class="function">(<span class="params">user, option</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'新增前'</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="comment">// 新增后</span></span><br><span class="line">    User.afterCreate(<span class="function">(<span class="params">user, option</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'新增后'</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="comment">// 修改前</span></span><br><span class="line">    User.beforeUpdate(<span class="function">(<span class="params">user, option</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'修改前'</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="comment">// 修改后</span></span><br><span class="line">    User.afterUpdate(<span class="function">(<span class="params">user, option</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'修改后'</span>); <span class="comment">// 真正修改才会触发，数据相同不会触发</span></span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="comment">// 删除前</span></span><br><span class="line">    User.beforeDestroy(<span class="function">(<span class="params">user, option</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'删除前'</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="comment">// 删除后</span></span><br><span class="line">    User.afterDestroy(<span class="function">(<span class="params">user, option</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'删除后'</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> User;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h2 id="查询"><a href="#查询" class="headerlink" title="查询"></a>查询</h2><h3 id="主键查询"><a href="#主键查询" class="headerlink" title="主键查询"></a>主键查询</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Model.findByPk(<span class="number">1</span>);</span><br></pre></td></tr></table></figure>

<h3 id="查找不存在则创建"><a href="#查找不存在则创建" class="headerlink" title="查找不存在则创建"></a>查找不存在则创建</h3><p>方法 <code>findOrCreate</code> 可用于检查数据库中是否已存在某个元素. 如果是这种情况,则该方法将生成相应的实例. 如果元素不存在,将会被创建.</p>
<p>如果是这种情况,则该方法将导致相应的实例. 如果元素不存在,将会被创建.</p>
<p>假设我们有一个空的数据库,一个 <code>User</code> 模型有一个 <code>username</code> 和 <code>job</code>.</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">User.findOrCreate(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    username: <span class="string">"sdepold"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  defaults: &#123;</span><br><span class="line">    job: <span class="string">"Technical Lead JavaScript"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;).then(<span class="function">(<span class="params">[user, created]</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(</span><br><span class="line">    user.get(&#123;</span><br><span class="line">      plain: <span class="literal">true</span>,</span><br><span class="line">    &#125;)</span><br><span class="line">  );</span><br><span class="line">  <span class="built_in">console</span>.log(created);</span><br><span class="line"></span><br><span class="line">  <span class="comment">/*</span></span><br><span class="line"><span class="comment">    findOrCreate 返回一个包含已找到或创建的对象的数组,找到或创建的对象和一个布尔值,如果创建一个新对象将为true,否则为false,像这样:</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">    [ &#123;</span></span><br><span class="line"><span class="comment">        username: 'sdepold',</span></span><br><span class="line"><span class="comment">        job: 'Technical Lead JavaScript',</span></span><br><span class="line"><span class="comment">        id: 1,</span></span><br><span class="line"><span class="comment">        createdAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET),</span></span><br><span class="line"><span class="comment">        updatedAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET)</span></span><br><span class="line"><span class="comment">      &#125;,</span></span><br><span class="line"><span class="comment">      true ]</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">在上面的例子中,第三行的数组将分成2部分,并将它们作为参数传递给回调函数,在这种情况下将它们视为 "user" 和 "created" .(所以“user”将是返回数组的索引0的对象,并且 "created" 将等于 "true".)</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>代码创建了一个新的实例. 所以当我们已经有一个实例了 …</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">User.create(&#123; <span class="attr">username</span>: <span class="string">"fnord"</span>, <span class="attr">job</span>: <span class="string">"omnomnom"</span> &#125;)</span><br><span class="line">  .then(<span class="function"><span class="params">()</span> =&gt;</span></span><br><span class="line">    User.findOrCreate(&#123;</span><br><span class="line">      where: &#123;</span><br><span class="line">        username: <span class="string">"fnord"</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">      defaults: &#123;</span><br><span class="line">        job: <span class="string">"something else"</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;)</span><br><span class="line">  )</span><br><span class="line">  .then(<span class="function">(<span class="params">[user, created]</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(</span><br><span class="line">      user.get(&#123;</span><br><span class="line">        plain: <span class="literal">true</span>,</span><br><span class="line">      &#125;)</span><br><span class="line">    );</span><br><span class="line">    <span class="built_in">console</span>.log(created);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">    在这个例子中,findOrCreate 返回一个如下的数组:</span></span><br><span class="line"><span class="comment">    [ &#123;</span></span><br><span class="line"><span class="comment">        username: 'fnord',</span></span><br><span class="line"><span class="comment">        job: 'omnomnom',</span></span><br><span class="line"><span class="comment">        id: 2,</span></span><br><span class="line"><span class="comment">        createdAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET),</span></span><br><span class="line"><span class="comment">        updatedAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET)</span></span><br><span class="line"><span class="comment">      &#125;,</span></span><br><span class="line"><span class="comment">      false</span></span><br><span class="line"><span class="comment">    ]</span></span><br><span class="line"><span class="comment">    由findOrCreate返回的数组通过第三行的数组扩展为两部分,并且这些部分将作为2个参数传递给回调函数,在这种情况下将其视为 "user" 和 "created" .(所以“user”将是返回数组的索引0的对象,并且 "created" 将等于 "false".)</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">  &#125;);</span><br></pre></td></tr></table></figure>

<p>…现有条目将不会更改. 看到第二个用户的 “job”,并且实际上创建操作是假的.</p>
<h3 id="查找并计数"><a href="#查找并计数" class="headerlink" title="查找并计数"></a>查找并计数</h3><p><code>findAndCountAll</code> - 在数据库中搜索多个元素,返回数据和总计数</p>
<p>这是一个方便的方法,它结合了 <code>findAll</code> 和 <code>count</code>(见下文),当处理与分页相关的查询时,这是有用的,你想用 <code>limit</code> 和 <code>offset</code> 检索数据,但也需要知道总数与查询匹配的记录数:</p>
<p>处理程序成功将始终接收具有两个属性的对象:</p>
<ul>
<li><code>count</code> - 一个整数,总数记录匹配 where 语句和关联的其它过滤器</li>
<li><code>rows</code> - 一个数组对象,记录在 limit 和 offset 范围内匹配 where 语句和关联的其它过滤器,</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">Project.findAndCountAll(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    title: &#123;</span><br><span class="line">      [Op.like]: <span class="string">"foo%"</span>,</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">  offset: <span class="number">10</span>,</span><br><span class="line">  limit: <span class="number">2</span>,</span><br><span class="line">&#125;).then(<span class="function">(<span class="params">result</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(result.count);</span><br><span class="line">  <span class="built_in">console</span>.log(result.rows);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>它支持 include. 只有标记为 <code>required</code> 的 include 将被添加到计数部分:</p>
<p>假设你想查找附有个人资料的所有用户:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">User.findAndCountAll(&#123;</span><br><span class="line">  include: [&#123; <span class="attr">model</span>: Profile, <span class="attr">required</span>: <span class="literal">true</span> &#125;],</span><br><span class="line">  limit: <span class="number">3</span>,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>因为 <code>Profile</code> 的 include 有 <code>required</code> 设置,这将导致内部连接,并且只有具有 profile 的用户将被计数. 如果我们从 include 中删除<code>required</code>,那么有和没有 profile 的用户都将被计数. 在 include 中添加一个 <code>where</code> 语句会自动使它成为 required:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">User.findAndCountAll(&#123;</span><br><span class="line">  include: [&#123; <span class="attr">model</span>: Profile, <span class="attr">where</span>: &#123; <span class="attr">active</span>: <span class="literal">true</span> &#125; &#125;],</span><br><span class="line">  limit: <span class="number">3</span>,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>上面的查询只会对具有 active profile 的用户进行计数,因为在将 where 语句添加到 include 时,<code>required</code> 被隐式设置为 true.</p>
<p>传递给 <code>findAndCountAll</code> 的 options 对象与 <code>findAll</code> 相同(如下所述).</p>
<h3 id="查询多个（常用）"><a href="#查询多个（常用）" class="headerlink" title="查询多个（常用）"></a>查询多个（常用）</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 找到多个条目</span></span><br><span class="line">Project.findAll().then(<span class="function">(<span class="params">projects</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// projects 将是所有 Project 实例的数组</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 搜索特定属性 - 使用哈希</span></span><br><span class="line">Project.findAll(&#123; <span class="attr">where</span>: &#123; <span class="attr">name</span>: <span class="string">"A Project"</span> &#125; &#125;).then(<span class="function">(<span class="params">projects</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// projects将是一个具有指定 name 的 Project 实例数组</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 在特定范围内进行搜索</span></span><br><span class="line">Project.findAll(&#123; <span class="attr">where</span>: &#123; <span class="attr">id</span>: [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>] &#125; &#125;).then(<span class="function">(<span class="params">projects</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// projects将是一系列具有 id 1,2 或 3 的项目</span></span><br><span class="line">  <span class="comment">// 这实际上是在做一个 IN 查询</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">Project.findAll(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    id: &#123;</span><br><span class="line">      [Op.and]: &#123; <span class="attr">a</span>: <span class="number">5</span> &#125;, <span class="comment">// 且 (a = 5)</span></span><br><span class="line">      [Op.or]: [&#123; <span class="attr">a</span>: <span class="number">5</span> &#125;, &#123; <span class="attr">a</span>: <span class="number">6</span> &#125;], <span class="comment">// (a = 5 或 a = 6)</span></span><br><span class="line">      [Op.gt]: <span class="number">6</span>, <span class="comment">// id &gt; 6</span></span><br><span class="line">      [Op.gte]: <span class="number">6</span>, <span class="comment">// id &gt;= 6</span></span><br><span class="line">      [Op.lt]: <span class="number">10</span>, <span class="comment">// id &lt; 10</span></span><br><span class="line">      [Op.lte]: <span class="number">10</span>, <span class="comment">// id &lt;= 10</span></span><br><span class="line">      [Op.ne]: <span class="number">20</span>, <span class="comment">// id != 20</span></span><br><span class="line">      [Op.between]: [<span class="number">6</span>, <span class="number">10</span>], <span class="comment">// 在 6 和 10 之间</span></span><br><span class="line">      [Op.notBetween]: [<span class="number">11</span>, <span class="number">15</span>], <span class="comment">// 不在 11 和 15 之间</span></span><br><span class="line">      [Op.in]: [<span class="number">1</span>, <span class="number">2</span>], <span class="comment">// 在 [1, 2] 之中</span></span><br><span class="line">      [Op.notIn]: [<span class="number">1</span>, <span class="number">2</span>], <span class="comment">// 不在 [1, 2] 之中</span></span><br><span class="line">      [Op.like]: <span class="string">"%hat"</span>, <span class="comment">// 包含 '%hat'</span></span><br><span class="line">      [Op.notLike]: <span class="string">"%hat"</span>, <span class="comment">// 不包含 '%hat'</span></span><br><span class="line">      [Op.iLike]: <span class="string">"%hat"</span>, <span class="comment">// 包含 '%hat' (不区分大小写)  (仅限 PG)</span></span><br><span class="line">      [Op.notILike]: <span class="string">"%hat"</span>, <span class="comment">// 不包含 '%hat'  (仅限 PG)</span></span><br><span class="line">      [Op.overlap]: [<span class="number">1</span>, <span class="number">2</span>], <span class="comment">// &amp;&amp; [1, 2] (PG数组重叠运算符)</span></span><br><span class="line">      [Op.contains]: [<span class="number">1</span>, <span class="number">2</span>], <span class="comment">// @&gt; [1, 2] (PG数组包含运算符)</span></span><br><span class="line">      [Op.contained]: [<span class="number">1</span>, <span class="number">2</span>], <span class="comment">// &lt;@ [1, 2] (PG数组包含于运算符)</span></span><br><span class="line">      [Op.any]: [<span class="number">2</span>, <span class="number">3</span>], <span class="comment">// 任何数组[2, 3]::INTEGER (仅限 PG)</span></span><br><span class="line">    &#125;,</span><br><span class="line">    status: &#123;</span><br><span class="line">      [Op.not]: <span class="literal">false</span>, <span class="comment">// status 不为 FALSE</span></span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="复合过滤-OR-NOT-查询"><a href="#复合过滤-OR-NOT-查询" class="headerlink" title="复合过滤 / OR / NOT 查询"></a>复合过滤 / OR / NOT 查询</h3><p>你可以使用多层嵌套的 AND,OR 和 NOT 条件进行一个复合的 where 查询. 为了做到这一点,你可以使用 <code>or</code> , <code>and</code> 或 <code>not</code> <code>运算符</code>:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">Project.findOne(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    name: <span class="string">"a project"</span>,</span><br><span class="line">    [Op.or]: [&#123; <span class="attr">id</span>: [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>] &#125;, &#123; <span class="attr">id</span>: &#123; [Op.gt]: <span class="number">10</span> &#125; &#125;],</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">Project.findOne(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    name: <span class="string">"a project"</span>,</span><br><span class="line">    id: &#123;</span><br><span class="line">      [Op.or]: [[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>], &#123; [Op.gt]: <span class="number">10</span> &#125;],</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>这两段代码将生成以下内容:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">SELECT *</span><br><span class="line">FROM <span class="string">`Projects`</span></span><br><span class="line">WHERE (</span><br><span class="line">  <span class="string">`Projects`</span>.<span class="string">`name`</span> = <span class="string">'a project'</span></span><br><span class="line">   AND (<span class="string">`Projects`</span>.<span class="string">`id`</span> IN (<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>) OR <span class="string">`Projects`</span>.<span class="string">`id`</span> &gt; <span class="number">10</span>)</span><br><span class="line">)</span><br><span class="line">LIMIT <span class="number">1</span>;</span><br></pre></td></tr></table></figure>

<p><code>not</code> 示例:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Project.findOne(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    name: <span class="string">"a project"</span>,</span><br><span class="line">    [Op.not]: [&#123; <span class="attr">id</span>: [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>] &#125;, &#123; <span class="attr">array</span>: &#123; [Op.contains]: [<span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>] &#125; &#125;],</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>将生成:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">SELECT *</span><br><span class="line">FROM <span class="string">`Projects`</span></span><br><span class="line">WHERE (</span><br><span class="line">  <span class="string">`Projects`</span>.<span class="string">`name`</span> = <span class="string">'a project'</span></span><br><span class="line">   AND NOT (<span class="string">`Projects`</span>.<span class="string">`id`</span> IN (<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>) OR <span class="string">`Projects`</span>.<span class="string">`array`</span> @&gt; ARRAY[<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>]::INTEGER[])</span><br><span class="line">)</span><br><span class="line">LIMIT <span class="number">1</span>;</span><br></pre></td></tr></table></figure>

<h3 id="用限制-偏移-顺序和分组操作数据集"><a href="#用限制-偏移-顺序和分组操作数据集" class="headerlink" title="用限制,偏移,顺序和分组操作数据集"></a>用限制,偏移,顺序和分组操作数据集</h3><p>要获取更多相关数据,可以使用限制,偏移,顺序和分组:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 限制查询的结果</span></span><br><span class="line">Project.findAll(&#123; <span class="attr">limit</span>: <span class="number">10</span> &#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 跳过前10个元素</span></span><br><span class="line">Project.findAll(&#123; <span class="attr">offset</span>: <span class="number">10</span> &#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 跳过前10个元素,并获取2个</span></span><br><span class="line">Project.findAll(&#123; <span class="attr">offset</span>: <span class="number">10</span>, <span class="attr">limit</span>: <span class="number">2</span> &#125;);</span><br></pre></td></tr></table></figure>

<p>分组和排序的语法是相同的,所以下面只用一个单独的例子来解释分组,而其余的则是排序. 你下面看到的所有内容也可以对分组进行</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Project.findAll(&#123; <span class="attr">order</span>: [[<span class="string">"title"</span>, <span class="string">"DESC"</span>]] &#125;);</span><br><span class="line"><span class="comment">// 生成 ORDER BY title DESC</span></span><br><span class="line"></span><br><span class="line">Project.findAll(&#123; <span class="attr">group</span>: <span class="string">"name"</span> &#125;);</span><br><span class="line"><span class="comment">// 生成 GROUP BY name</span></span><br></pre></td></tr></table></figure>

<p>请注意,在上述两个示例中,提供的字符串逐字插入到查询中,所以不会转义列名称. 当你向 order / group 提供字符串时,将始终如此. 如果要转义列名,你应该提供一个参数数组,即使你只想通过单个列进行 order / group</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">something.findOne(&#123;</span><br><span class="line">  order: [</span><br><span class="line">    <span class="comment">// 将返回 `name`</span></span><br><span class="line">    [<span class="string">"name"</span>],</span><br><span class="line">    <span class="comment">// 将返回 `username` DESC</span></span><br><span class="line">    [<span class="string">"username"</span>, <span class="string">"DESC"</span>],</span><br><span class="line">    <span class="comment">// 将返回 max(`age`)</span></span><br><span class="line">    sequelize.fn(<span class="string">"max"</span>, sequelize.col(<span class="string">"age"</span>)),</span><br><span class="line">    <span class="comment">// 将返回 max(`age`) DESC</span></span><br><span class="line">    [sequelize.fn(<span class="string">"max"</span>, sequelize.col(<span class="string">"age"</span>)), <span class="string">"DESC"</span>],</span><br><span class="line">    <span class="comment">// 将返回 otherfunction(`col1`, 12, 'lalala') DESC</span></span><br><span class="line">    [</span><br><span class="line">      sequelize.fn(<span class="string">"otherfunction"</span>, sequelize.col(<span class="string">"col1"</span>), <span class="number">12</span>, <span class="string">"lalala"</span>),</span><br><span class="line">      <span class="string">"DESC"</span>,</span><br><span class="line">    ],</span><br><span class="line">    <span class="comment">// 将返回 otherfunction(awesomefunction(`col`)) DESC,这个嵌套是可以无限的！</span></span><br><span class="line">    [</span><br><span class="line">      sequelize.fn(</span><br><span class="line">        <span class="string">"otherfunction"</span>,</span><br><span class="line">        sequelize.fn(<span class="string">"awesomefunction"</span>, sequelize.col(<span class="string">"col"</span>))</span><br><span class="line">      ),</span><br><span class="line">      <span class="string">"DESC"</span>,</span><br><span class="line">    ],</span><br><span class="line">  ],</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>回顾一下,order / group 数组的元素可以是以下内容:</p>
<ul>
<li>String - 将被引用</li>
<li>Array - 第一个元素将被引用,第二个将被逐字地追加</li>
<li>Object -<ul>
<li>raw 将被添加逐字引用</li>
<li>如果未设置 raw,一切都被忽略,查询将失败</li>
</ul>
</li>
<li>Sequelize.fn 和 Sequelize.col 返回函数和引用的列名</li>
</ul>
<h3 id="字段过滤"><a href="#字段过滤" class="headerlink" title="字段过滤"></a>字段过滤</h3><p>想要只选择某些属性,可以使用 <code>attributes</code> 选项. 通常是传递一个数组:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Model.findAll(&#123;</span><br><span class="line">  attributes: [<span class="string">"foo"</span>, <span class="string">"bar"</span>],</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<blockquote>
<p>SELECT foo, bar …</p>
</blockquote>
<p>属性可以使用嵌套数组来重命名:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Model.findAll(&#123;</span><br><span class="line">  attributes: [<span class="string">"foo"</span>, [<span class="string">"bar"</span>, <span class="string">"baz"</span>]],</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<blockquote>
<p>SELECT foo, bar AS baz …</p>
</blockquote>
<p>也可以使用 <code>sequelize.fn</code> 来进行聚合:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Model.findAll(&#123;</span><br><span class="line">  attributes: [[sequelize.fn(<span class="string">"COUNT"</span>, sequelize.col(<span class="string">"hats"</span>)), <span class="string">"no_hats"</span>]],</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<blockquote>
<p>SELECT COUNT(hats) AS no_hats …</p>
</blockquote>
<p>使用聚合功能时,必须给它一个别名,以便能够从模型中访问它. 在上面的例子中,你可以使用 <code>instance.get(&#39;no_hats&#39;)</code> 获得帽子数量.</p>
<p>有时,如果你只想添加聚合,则列出模型的所有属性可能令人厌烦:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// This is a tiresome way of getting the number of hats...</span></span><br><span class="line">Model.findAll(&#123;</span><br><span class="line">  attributes: [<span class="string">'id'</span>, <span class="string">'foo'</span>, <span class="string">'bar'</span>, <span class="string">'baz'</span>, <span class="string">'quz'</span>, [sequelize.fn(<span class="string">'COUNT'</span>, sequelize.col(<span class="string">'hats'</span>)), <span class="string">'no_hats'</span>]]</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// This is shorter, and less error prone because it still works if you add / remove attributes</span></span><br><span class="line">Model.findAll(&#123;</span><br><span class="line">  attributes: &#123; <span class="attr">include</span>: [[sequelize.fn(<span class="string">'COUNT'</span>, sequelize.col(<span class="string">'hats'</span>)), <span class="string">'no_hats'</span>]] &#125;</span><br><span class="line">&#125;);</span><br><span class="line">SELECT id, foo, bar, baz, quz, COUNT(hats) AS no_hats ...</span><br></pre></td></tr></table></figure>

<p>同样,它也可以排除一些指定的表字段:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Model.findAll(&#123;</span><br><span class="line">  attributes: &#123; <span class="attr">exclude</span>: [<span class="string">'baz'</span>] &#125;</span><br><span class="line">&#125;);</span><br><span class="line">SELECT id, foo, bar, quz ...</span><br></pre></td></tr></table></figure>

<h3 id="Where"><a href="#Where" class="headerlink" title="Where"></a>Where</h3><p>无论你是通过 findAll/find 或批量 updates/destroys 进行查询,都可以传递一个 <code>where</code> 对象来过滤查询.</p>
<p><code>where</code> 通常用 attribute:value 键值对获取一个对象,其中 value 可以是匹配等式的数据或其他运算符的键值对象.</p>
<p>也可以通过嵌套 <code>or</code> 和 <code>and</code> <code>运算符</code> 的集合来生成复杂的 AND/OR 条件.</p>
<h4 id="基础"><a href="#基础" class="headerlink" title="基础"></a>基础</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> Op = Sequelize.Op;</span><br><span class="line"></span><br><span class="line">Post.findAll(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    authorId: <span class="number">2</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// SELECT * FROM post WHERE authorId = 2</span></span><br><span class="line"></span><br><span class="line">Post.findAll(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    authorId: <span class="number">12</span>,</span><br><span class="line">    status: <span class="string">"active"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// SELECT * FROM post WHERE authorId = 12 AND status = 'active';</span></span><br><span class="line"></span><br><span class="line">Post.findAll(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    [Op.or]: [&#123; <span class="attr">authorId</span>: <span class="number">12</span> &#125;, &#123; <span class="attr">authorId</span>: <span class="number">13</span> &#125;],</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// SELECT * FROM post WHERE authorId = 12 OR authorId = 13;</span></span><br><span class="line"></span><br><span class="line">Post.findAll(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    authorId: &#123;</span><br><span class="line">      [Op.or]: [<span class="number">12</span>, <span class="number">13</span>],</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// SELECT * FROM post WHERE authorId = 12 OR authorId = 13;</span></span><br><span class="line"></span><br><span class="line">Post.destroy(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    status: <span class="string">"inactive"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// DELETE FROM post WHERE status = 'inactive';</span></span><br><span class="line"></span><br><span class="line">Post.update(</span><br><span class="line">  &#123;</span><br><span class="line">    updatedAt: <span class="literal">null</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    where: &#123;</span><br><span class="line">      deletedAt: &#123;</span><br><span class="line">        [Op.ne]: <span class="literal">null</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;</span><br><span class="line">);</span><br><span class="line"><span class="comment">// UPDATE post SET updatedAt = null WHERE deletedAt NOT NULL;</span></span><br><span class="line"></span><br><span class="line">Post.findAll(&#123;</span><br><span class="line">  where: sequelize.where(</span><br><span class="line">    sequelize.fn(<span class="string">"char_length"</span>, sequelize.col(<span class="string">"status"</span>)),</span><br><span class="line">    <span class="number">6</span></span><br><span class="line">  ),</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// SELECT * FROM post WHERE char_length(status) = 6;</span></span><br></pre></td></tr></table></figure>

<h4 id="操作符"><a href="#操作符" class="headerlink" title="操作符"></a>操作符</h4><p>Sequelize 可用于创建更复杂比较的符号运算符 -</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> Op = Sequelize.Op</span><br><span class="line"></span><br><span class="line">[Op.and]: &#123;<span class="attr">a</span>: <span class="number">5</span>&#125;           <span class="comment">// 且 (a = 5)</span></span><br><span class="line">[Op.or]: [&#123;<span class="attr">a</span>: <span class="number">5</span>&#125;, &#123;<span class="attr">a</span>: <span class="number">6</span>&#125;]  <span class="comment">// (a = 5 或 a = 6)</span></span><br><span class="line">[Op.gt]: <span class="number">6</span>,                <span class="comment">// id &gt; 6</span></span><br><span class="line">[Op.gte]: <span class="number">6</span>,               <span class="comment">// id &gt;= 6</span></span><br><span class="line">[Op.lt]: <span class="number">10</span>,               <span class="comment">// id &lt; 10</span></span><br><span class="line">[Op.lte]: <span class="number">10</span>,              <span class="comment">// id &lt;= 10</span></span><br><span class="line">[Op.ne]: <span class="number">20</span>,               <span class="comment">// id != 20</span></span><br><span class="line">[Op.eq]: <span class="number">3</span>,                <span class="comment">// = 3</span></span><br><span class="line">[Op.not]: <span class="literal">true</span>,            <span class="comment">// 不是 TRUE</span></span><br><span class="line">[Op.between]: [<span class="number">6</span>, <span class="number">10</span>],     <span class="comment">// 在 6 和 10 之间</span></span><br><span class="line">[Op.notBetween]: [<span class="number">11</span>, <span class="number">15</span>], <span class="comment">// 不在 11 和 15 之间</span></span><br><span class="line">[Op.in]: [<span class="number">1</span>, <span class="number">2</span>],           <span class="comment">// 在 [1, 2] 之中</span></span><br><span class="line">[Op.notIn]: [<span class="number">1</span>, <span class="number">2</span>],        <span class="comment">// 不在 [1, 2] 之中</span></span><br><span class="line">[Op.like]: <span class="string">'%hat'</span>,         <span class="comment">// 包含 '%hat'</span></span><br><span class="line">[Op.notLike]: <span class="string">'%hat'</span>       <span class="comment">// 不包含 '%hat'</span></span><br><span class="line">[Op.iLike]: <span class="string">'%hat'</span>         <span class="comment">// 包含 '%hat' (不区分大小写)  (仅限 PG)</span></span><br><span class="line">[Op.notILike]: <span class="string">'%hat'</span>      <span class="comment">// 不包含 '%hat'  (仅限 PG)</span></span><br><span class="line">[Op.startsWith]: <span class="string">'hat'</span>     <span class="comment">// 类似 'hat%'</span></span><br><span class="line">[Op.endsWith]: <span class="string">'hat'</span>       <span class="comment">// 类似 '%hat'</span></span><br><span class="line">[Op.substring]: <span class="string">'hat'</span>      <span class="comment">// 类似 '%hat%'</span></span><br><span class="line">[Op.regexp]: <span class="string">'^[h|a|t]'</span>    <span class="comment">// 匹配正则表达式/~ '^[h|a|t]' (仅限 MySQL/PG)</span></span><br><span class="line">[Op.notRegexp]: <span class="string">'^[h|a|t]'</span> <span class="comment">// 不匹配正则表达式/!~ '^[h|a|t]' (仅限 MySQL/PG)</span></span><br><span class="line">[Op.iRegexp]: <span class="string">'^[h|a|t]'</span>    <span class="comment">// ~* '^[h|a|t]' (仅限 PG)</span></span><br><span class="line">[Op.notIRegexp]: <span class="string">'^[h|a|t]'</span> <span class="comment">// !~* '^[h|a|t]' (仅限 PG)</span></span><br><span class="line">[Op.like]: &#123; [Op.any]: [<span class="string">'cat'</span>, <span class="string">'hat'</span>]&#125; <span class="comment">// 包含任何数组['cat', 'hat'] - 同样适用于 iLike 和 notLike</span></span><br><span class="line">[Op.overlap]: [<span class="number">1</span>, <span class="number">2</span>]       <span class="comment">// &amp;&amp; [1, 2] (PG数组重叠运算符)</span></span><br><span class="line">[Op.contains]: [<span class="number">1</span>, <span class="number">2</span>]      <span class="comment">// @&gt; [1, 2] (PG数组包含运算符)</span></span><br><span class="line">[Op.contained]: [<span class="number">1</span>, <span class="number">2</span>]     <span class="comment">// &lt;@ [1, 2] (PG数组包含于运算符)</span></span><br><span class="line">[Op.any]: [<span class="number">2</span>,<span class="number">3</span>]            <span class="comment">// 任何数组[2, 3]::INTEGER (仅限PG)</span></span><br><span class="line"></span><br><span class="line">[Op.col]: <span class="string">'user.organization_id'</span> <span class="comment">// = 'user'.'organization_id', 使用数据库语言特定的列标识符, 本例使用 PG</span></span><br></pre></td></tr></table></figure>

<h4 id="范围选项"><a href="#范围选项" class="headerlink" title="范围选项"></a>范围选项</h4><p>所有操作符都支持支持的范围类型查询.</p>
<p>请记住,提供的范围值也可以<a href="https://itfun.tv/documents/266#range-types" target="_blank" rel="noopener">定义绑定的 inclusion/exclusion</a>.</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 所有上述相等和不相等的操作符加上以下内容:</span></span><br><span class="line"></span><br><span class="line">[Op.contains]: <span class="number">2</span>           <span class="comment">// @&gt; '2'::integer (PG range contains element operator)</span></span><br><span class="line">[Op.contains]: [<span class="number">1</span>, <span class="number">2</span>]      <span class="comment">// @&gt; [1, 2) (PG range contains range operator)</span></span><br><span class="line">[Op.contained]: [<span class="number">1</span>, <span class="number">2</span>]     <span class="comment">// &lt;@ [1, 2) (PG range is contained by operator)</span></span><br><span class="line">[Op.overlap]: [<span class="number">1</span>, <span class="number">2</span>]       <span class="comment">// &amp;&amp; [1, 2) (PG range overlap (have points in common) operator)</span></span><br><span class="line">[Op.adjacent]: [<span class="number">1</span>, <span class="number">2</span>]      <span class="comment">// -|- [1, 2) (PG range is adjacent to operator)</span></span><br><span class="line">[Op.strictLeft]: [<span class="number">1</span>, <span class="number">2</span>]    <span class="comment">// &lt;&lt; [1, 2) (PG range strictly left of operator)</span></span><br><span class="line">[Op.strictRight]: [<span class="number">1</span>, <span class="number">2</span>]   <span class="comment">// &gt;&gt; [1, 2) (PG range strictly right of operator)</span></span><br><span class="line">[Op.noExtendRight]: [<span class="number">1</span>, <span class="number">2</span>] <span class="comment">// &amp;&lt; [1, 2) (PG range does not extend to the right of operator)</span></span><br><span class="line">[Op.noExtendLeft]: [<span class="number">1</span>, <span class="number">2</span>]  <span class="comment">// &amp;&gt; [1, 2) (PG range does not extend to the left of operator)</span></span><br></pre></td></tr></table></figure>

<h4 id="组合"><a href="#组合" class="headerlink" title="组合"></a>组合</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  rank: &#123;</span><br><span class="line">    [Op.or]: &#123;</span><br><span class="line">      [Op.lt]: <span class="number">1000</span>,</span><br><span class="line">      [Op.eq]: <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// rank &lt; 1000 OR rank IS NULL</span></span><br><span class="line"></span><br><span class="line">&#123;</span><br><span class="line">  createdAt: &#123;</span><br><span class="line">    [Op.lt]: <span class="keyword">new</span> <span class="built_in">Date</span>(),</span><br><span class="line">    [Op.gt]: <span class="keyword">new</span> <span class="built_in">Date</span>(<span class="keyword">new</span> <span class="built_in">Date</span>() - <span class="number">24</span> * <span class="number">60</span> * <span class="number">60</span> * <span class="number">1000</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// createdAt &lt; [timestamp] AND createdAt &gt; [timestamp]</span></span><br><span class="line"></span><br><span class="line">&#123;</span><br><span class="line">  [Op.or]: [</span><br><span class="line">    &#123;</span><br><span class="line">      title: &#123;</span><br><span class="line">        [Op.like]: <span class="string">'Boat%'</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      description: &#123;</span><br><span class="line">        [Op.like]: <span class="string">'%boat%'</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// title LIKE 'Boat%' OR description LIKE '%boat%'</span></span><br></pre></td></tr></table></figure>

<h4 id="关系-关联"><a href="#关系-关联" class="headerlink" title="关系 / 关联"></a>关系 / 关联</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 找到所有具有至少一个 task 的  project,其中 task.state === project.state</span></span><br><span class="line">Project.findAll(&#123;</span><br><span class="line">  include: [</span><br><span class="line">    &#123;</span><br><span class="line">      model: Task,</span><br><span class="line">      where: &#123; <span class="attr">state</span>: Sequelize.col(<span class="string">"project.state"</span>) &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">  ],</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="分页-限制"><a href="#分页-限制" class="headerlink" title="分页 / 限制"></a>分页 / 限制</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取10个实例/行</span></span><br><span class="line">Project.findAll(&#123; <span class="attr">limit</span>: <span class="number">10</span> &#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 跳过8个实例/行</span></span><br><span class="line">Project.findAll(&#123; <span class="attr">offset</span>: <span class="number">8</span> &#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 跳过5个实例,然后取5个</span></span><br><span class="line">Project.findAll(&#123; <span class="attr">offset</span>: <span class="number">5</span>, <span class="attr">limit</span>: <span class="number">5</span> &#125;);</span><br></pre></td></tr></table></figure>

<h3 id="排序"><a href="#排序" class="headerlink" title="排序"></a>排序</h3><p><code>order</code> 需要一个条目的数组来排序查询或者一个 sequelize 方法.一般来说,你将要使用任一属性的 tuple/array,并确定排序的正反方向.</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">Subtask.findAll(&#123;</span><br><span class="line">  order: [</span><br><span class="line">    <span class="comment">// 将转义标题,并根据有效的方向参数列表验证DESC</span></span><br><span class="line">    [<span class="string">'title'</span>, <span class="string">'DESC'</span>],</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 将按最大值排序(age)</span></span><br><span class="line">    sequelize.fn(<span class="string">'max'</span>, sequelize.col(<span class="string">'age'</span>)),</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 将按最大顺序(age) DESC</span></span><br><span class="line">    [sequelize.fn(<span class="string">'max'</span>, sequelize.col(<span class="string">'age'</span>)), <span class="string">'DESC'</span>],</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 将按 otherfunction 排序(`col1`, 12, 'lalala') DESC</span></span><br><span class="line">    [sequelize.fn(<span class="string">'otherfunction'</span>, sequelize.col(<span class="string">'col1'</span>), <span class="number">12</span>, <span class="string">'lalala'</span>), <span class="string">'DESC'</span>],</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 将使用模型名称作为关联的名称排序关联模型的 created_at.</span></span><br><span class="line">    [Task, <span class="string">'createdAt'</span>, <span class="string">'DESC'</span>],</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Will order through an associated model's created_at using the model names as the associations' names.</span></span><br><span class="line">    [Task, Project, <span class="string">'createdAt'</span>, <span class="string">'DESC'</span>],</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 将使用关联的名称由关联模型的created_at排序.</span></span><br><span class="line">    [<span class="string">'Task'</span>, <span class="string">'createdAt'</span>, <span class="string">'DESC'</span>],</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Will order by a nested associated model's created_at using the names of the associations.</span></span><br><span class="line">    [<span class="string">'Task'</span>, <span class="string">'Project'</span>, <span class="string">'createdAt'</span>, <span class="string">'DESC'</span>],</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Will order by an associated model's created_at using an association object. (优选方法)</span></span><br><span class="line">    [Subtask.associations.Task, <span class="string">'createdAt'</span>, <span class="string">'DESC'</span>],</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Will order by a nested associated model's created_at using association objects. (优选方法)</span></span><br><span class="line">    [Subtask.associations.Task, Task.associations.Project, <span class="string">'createdAt'</span>, <span class="string">'DESC'</span>],</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Will order by an associated model's created_at using a simple association object.</span></span><br><span class="line">    [&#123;<span class="attr">model</span>: Task, <span class="attr">as</span>: <span class="string">'Task'</span>&#125;, <span class="string">'createdAt'</span>, <span class="string">'DESC'</span>],</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 嵌套关联模型的 created_at 简单关联对象排序</span></span><br><span class="line">    [&#123;<span class="attr">model</span>: Task, <span class="attr">as</span>: <span class="string">'Task'</span>&#125;, &#123;<span class="attr">model</span>: Project, <span class="attr">as</span>: <span class="string">'Project'</span>&#125;, <span class="string">'createdAt'</span>, <span class="string">'DESC'</span>]</span><br><span class="line">  ]</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 将按年龄最大值降序排列</span></span><br><span class="line">  order: sequelize.literal(<span class="string">'max(age) DESC'</span>)</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 按最年龄大值升序排列,当省略排序条件时默认是升序排列</span></span><br><span class="line">  order: sequelize.fn(<span class="string">'max'</span>, sequelize.col(<span class="string">'age'</span>))</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 按升序排列是省略排序条件的默认顺序</span></span><br><span class="line">  order: sequelize.col(<span class="string">'age'</span>)</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 将根据方言随机排序 (而不是 fn('RAND') 或 fn('RANDOM'))</span></span><br><span class="line">  order: sequelize.random()</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<h3 id="count-计算数据库中元素的出现次数"><a href="#count-计算数据库中元素的出现次数" class="headerlink" title="count - 计算数据库中元素的出现次数"></a><code>count</code> - 计算数据库中元素的出现次数</h3><p>还有一种数据库对象计数的方法:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Project.count().then(<span class="function">(<span class="params">c</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">"There are "</span> + c + <span class="string">" projects!"</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">Project.count(&#123; <span class="attr">where</span>: &#123; <span class="attr">id</span>: &#123; [Op.gt]: <span class="number">25</span> &#125; &#125; &#125;).then(<span class="function">(<span class="params">c</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">"There are "</span> + c + <span class="string">" projects with an id greater than 25."</span>);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="max-获取特定表中特定属性的最大值"><a href="#max-获取特定表中特定属性的最大值" class="headerlink" title="max - 获取特定表中特定属性的最大值"></a><code>max</code> - 获取特定表中特定属性的最大值</h3><p>这里是获取属性的最大值的方法:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">   我们假设3个具有属性年龄的对象.</span></span><br><span class="line"><span class="comment">   第一个是10岁,</span></span><br><span class="line"><span class="comment">   第二个是5岁,</span></span><br><span class="line"><span class="comment">   第三个是40岁.</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">Project.max(<span class="string">"age"</span>).then(<span class="function">(<span class="params">max</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 将返回 40</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">Project.max(<span class="string">"age"</span>, &#123; <span class="attr">where</span>: &#123; <span class="attr">age</span>: &#123; [Op.lt]: <span class="number">20</span> &#125; &#125; &#125;).then(<span class="function">(<span class="params">max</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 将会是 10</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="min-获取特定表中特定属性的最小值"><a href="#min-获取特定表中特定属性的最小值" class="headerlink" title="min - 获取特定表中特定属性的最小值"></a><code>min</code> - 获取特定表中特定属性的最小值</h3><p>这里是获取属性的最小值的方法:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">   我们假设3个具有属性年龄的对象.</span></span><br><span class="line"><span class="comment">   第一个是10岁,</span></span><br><span class="line"><span class="comment">   第二个是5岁,</span></span><br><span class="line"><span class="comment">   第三个是40岁.</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">Project.min(<span class="string">"age"</span>).then(<span class="function">(<span class="params">min</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 将返回 5</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">Project.min(<span class="string">"age"</span>, &#123; <span class="attr">where</span>: &#123; <span class="attr">age</span>: &#123; [Op.gt]: <span class="number">5</span> &#125; &#125; &#125;).then(<span class="function">(<span class="params">min</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 将会是 10</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="sum-特定属性的值求和"><a href="#sum-特定属性的值求和" class="headerlink" title="sum - 特定属性的值求和"></a><code>sum</code> - 特定属性的值求和</h3><p>为了计算表的特定列的总和,可以使用“sum”方法.</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">   我们假设3个具有属性年龄的对象.</span></span><br><span class="line"><span class="comment">   第一个是10岁,</span></span><br><span class="line"><span class="comment">   第二个是5岁,</span></span><br><span class="line"><span class="comment">   第三个是40岁.</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">Project.sum(<span class="string">"age"</span>).then(<span class="function">(<span class="params">sum</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 将返回 55</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">Project.sum(<span class="string">"age"</span>, &#123; <span class="attr">where</span>: &#123; <span class="attr">age</span>: &#123; [Op.gt]: <span class="number">5</span> &#125; &#125; &#125;).then(<span class="function">(<span class="params">sum</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 将会是 50</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h2 id="预加载"><a href="#预加载" class="headerlink" title="预加载"></a>预加载</h2><p>当你从数据库检索数据时,也想同时获得与之相关联的查询,这被称为预加载.这个基本思路就是当你调用 <code>find</code> 或 <code>findAll</code> 时使用 <code>include</code> 属性.让我们假设以下设置:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span> <span class="keyword">extends</span> <span class="title">Model</span> </span>&#123;&#125;</span><br><span class="line">User.init(&#123; <span class="attr">name</span>: Sequelize.STRING &#125;, &#123; sequelize, <span class="attr">modelName</span>: <span class="string">"user"</span> &#125;);</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Task</span> <span class="keyword">extends</span> <span class="title">Model</span> </span>&#123;&#125;</span><br><span class="line">Task.init(&#123; <span class="attr">name</span>: Sequelize.STRING &#125;, &#123; sequelize, <span class="attr">modelName</span>: <span class="string">"task"</span> &#125;);</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Tool</span> <span class="keyword">extends</span> <span class="title">Model</span> </span>&#123;&#125;</span><br><span class="line">Tool.init(&#123; <span class="attr">name</span>: Sequelize.STRING &#125;, &#123; sequelize, <span class="attr">modelName</span>: <span class="string">"tool"</span> &#125;);</span><br><span class="line"></span><br><span class="line">Task.belongsTo(User);</span><br><span class="line">User.hasMany(Task);</span><br><span class="line">User.hasMany(Tool, &#123; <span class="attr">as</span>: <span class="string">"Instruments"</span> &#125;);</span><br><span class="line"></span><br><span class="line">sequelize.sync().then(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 这是我们继续的地方 ...</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>首先,让我们用它们的关联 user 加载所有的 task.</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">Task.findAll(&#123; <span class="attr">include</span>: [User] &#125;).then(<span class="function">(<span class="params">tasks</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="built_in">JSON</span>.stringify(tasks));</span><br><span class="line"></span><br><span class="line">  <span class="comment">/*</span></span><br><span class="line"><span class="comment">    [&#123;</span></span><br><span class="line"><span class="comment">      "name": "A Task",</span></span><br><span class="line"><span class="comment">      "id": 1,</span></span><br><span class="line"><span class="comment">      "createdAt": "2013-03-20T20:31:40.000Z",</span></span><br><span class="line"><span class="comment">      "updatedAt": "2013-03-20T20:31:40.000Z",</span></span><br><span class="line"><span class="comment">      "userId": 1,</span></span><br><span class="line"><span class="comment">      "user": &#123;</span></span><br><span class="line"><span class="comment">        "name": "John Doe",</span></span><br><span class="line"><span class="comment">        "id": 1,</span></span><br><span class="line"><span class="comment">        "createdAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">        "updatedAt": "2013-03-20T20:31:45.000Z"</span></span><br><span class="line"><span class="comment">      &#125;</span></span><br><span class="line"><span class="comment">    &#125;]</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>请注意,访问者(结果实例中的 <code>User</code> 属性)是单数形式,因为关联是一对一的.</p>
<p>接下来的事情:用多对一的关联加载数据！</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">User.findAll(&#123; <span class="attr">include</span>: [Task] &#125;).then(<span class="function">(<span class="params">users</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="built_in">JSON</span>.stringify(users));</span><br><span class="line"></span><br><span class="line">  <span class="comment">/*</span></span><br><span class="line"><span class="comment">    [&#123;</span></span><br><span class="line"><span class="comment">      "name": "John Doe",</span></span><br><span class="line"><span class="comment">      "id": 1,</span></span><br><span class="line"><span class="comment">      "createdAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">      "updatedAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">      "tasks": [&#123;</span></span><br><span class="line"><span class="comment">        "name": "A Task",</span></span><br><span class="line"><span class="comment">        "id": 1,</span></span><br><span class="line"><span class="comment">        "createdAt": "2013-03-20T20:31:40.000Z",</span></span><br><span class="line"><span class="comment">        "updatedAt": "2013-03-20T20:31:40.000Z",</span></span><br><span class="line"><span class="comment">        "userId": 1</span></span><br><span class="line"><span class="comment">      &#125;]</span></span><br><span class="line"><span class="comment">    &#125;]</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>请注意,访问者(结果实例中的 <code>Tasks</code> 属性)是复数形式,因为关联是多对一的.</p>
<p>如果关联是别名的(使用 <code>as</code> 参数),则在包含模型时必须指定此别名. 注意用户的 <code>Tool</code> 如何被别名为 <code>Instruments</code>. 为了获得正确的权限,你必须指定要加载的模型以及别名:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">User.findAll(&#123; <span class="attr">include</span>: [&#123; <span class="attr">model</span>: Tool, <span class="attr">as</span>: <span class="string">"Instruments"</span> &#125;] &#125;).then(</span><br><span class="line">  (users) =&gt; &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="built_in">JSON</span>.stringify(users));</span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">    [&#123;</span></span><br><span class="line"><span class="comment">      "name": "John Doe",</span></span><br><span class="line"><span class="comment">      "id": 1,</span></span><br><span class="line"><span class="comment">      "createdAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">      "updatedAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">      "Instruments": [&#123;</span></span><br><span class="line"><span class="comment">        "name": "Toothpick",</span></span><br><span class="line"><span class="comment">        "id": 1,</span></span><br><span class="line"><span class="comment">        "createdAt": null,</span></span><br><span class="line"><span class="comment">        "updatedAt": null,</span></span><br><span class="line"><span class="comment">        "userId": 1</span></span><br><span class="line"><span class="comment">      &#125;]</span></span><br><span class="line"><span class="comment">    &#125;]</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">  &#125;</span><br><span class="line">);</span><br></pre></td></tr></table></figure>

<p>你还可以通过指定与关联别名匹配的字符串来包含别名:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">User.findAll(&#123; <span class="attr">include</span>: [<span class="string">"Instruments"</span>] &#125;).then(<span class="function">(<span class="params">users</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="built_in">JSON</span>.stringify(users));</span><br><span class="line"></span><br><span class="line">  <span class="comment">/*</span></span><br><span class="line"><span class="comment">    [&#123;</span></span><br><span class="line"><span class="comment">      "name": "John Doe",</span></span><br><span class="line"><span class="comment">      "id": 1,</span></span><br><span class="line"><span class="comment">      "createdAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">      "updatedAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">      "Instruments": [&#123;</span></span><br><span class="line"><span class="comment">        "name": "Toothpick",</span></span><br><span class="line"><span class="comment">        "id": 1,</span></span><br><span class="line"><span class="comment">        "createdAt": null,</span></span><br><span class="line"><span class="comment">        "updatedAt": null,</span></span><br><span class="line"><span class="comment">        "userId": 1</span></span><br><span class="line"><span class="comment">      &#125;]</span></span><br><span class="line"><span class="comment">    &#125;]</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">User.findAll(&#123; <span class="attr">include</span>: [&#123; <span class="attr">association</span>: <span class="string">"Instruments"</span> &#125;] &#125;).then(<span class="function">(<span class="params">users</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="built_in">JSON</span>.stringify(users));</span><br><span class="line"></span><br><span class="line">  <span class="comment">/*</span></span><br><span class="line"><span class="comment">    [&#123;</span></span><br><span class="line"><span class="comment">      "name": "John Doe",</span></span><br><span class="line"><span class="comment">      "id": 1,</span></span><br><span class="line"><span class="comment">      "createdAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">      "updatedAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">      "Instruments": [&#123;</span></span><br><span class="line"><span class="comment">        "name": "Toothpick",</span></span><br><span class="line"><span class="comment">        "id": 1,</span></span><br><span class="line"><span class="comment">        "createdAt": null,</span></span><br><span class="line"><span class="comment">        "updatedAt": null,</span></span><br><span class="line"><span class="comment">        "userId": 1</span></span><br><span class="line"><span class="comment">      &#125;]</span></span><br><span class="line"><span class="comment">    &#125;]</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>当预加载时,我们也可以使用 <code>where</code> 过滤关联的模型. 这将返回 <code>Tool</code> 模型中所有与 <code>where</code> 语句匹配的行的<code>User</code>.</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">User.findAll(&#123;</span><br><span class="line">  include: [</span><br><span class="line">    &#123;</span><br><span class="line">      model: Tool,</span><br><span class="line">      <span class="keyword">as</span>: <span class="string">"Instruments"</span>,</span><br><span class="line">      where: &#123; <span class="attr">name</span>: &#123; [Op.like]: <span class="string">"%ooth%"</span> &#125; &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">  ],</span><br><span class="line">&#125;).then(<span class="function">(<span class="params">users</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="built_in">JSON</span>.stringify(users));</span><br><span class="line"></span><br><span class="line">  <span class="comment">/*</span></span><br><span class="line"><span class="comment">      [&#123;</span></span><br><span class="line"><span class="comment">        "name": "John Doe",</span></span><br><span class="line"><span class="comment">        "id": 1,</span></span><br><span class="line"><span class="comment">        "createdAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">        "updatedAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">        "Instruments": [&#123;</span></span><br><span class="line"><span class="comment">          "name": "Toothpick",</span></span><br><span class="line"><span class="comment">          "id": 1,</span></span><br><span class="line"><span class="comment">          "createdAt": null,</span></span><br><span class="line"><span class="comment">          "updatedAt": null,</span></span><br><span class="line"><span class="comment">          "userId": 1</span></span><br><span class="line"><span class="comment">        &#125;]</span></span><br><span class="line"><span class="comment">      &#125;],</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">      [&#123;</span></span><br><span class="line"><span class="comment">        "name": "John Smith",</span></span><br><span class="line"><span class="comment">        "id": 2,</span></span><br><span class="line"><span class="comment">        "createdAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">        "updatedAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">        "Instruments": [&#123;</span></span><br><span class="line"><span class="comment">          "name": "Toothpick",</span></span><br><span class="line"><span class="comment">          "id": 1,</span></span><br><span class="line"><span class="comment">          "createdAt": null,</span></span><br><span class="line"><span class="comment">          "updatedAt": null,</span></span><br><span class="line"><span class="comment">          "userId": 1</span></span><br><span class="line"><span class="comment">        &#125;]</span></span><br><span class="line"><span class="comment">      &#125;],</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>当使用 <code>include.where</code> 过滤一个预加载的模型时,<code>include.required</code> 被隐式设置为 <code>true</code>. 这意味着内部联接完成返回具有任何匹配子项的父模型.</p>
<h3 id="使用预加载模型的顶层-WHERE"><a href="#使用预加载模型的顶层-WHERE" class="headerlink" title="使用预加载模型的顶层 WHERE"></a>使用预加载模型的顶层 WHERE</h3><p>将模型的 <code>WHERE</code> 条件从 <code>ON</code> 条件的 include 模式移动到顶层,你可以使用 <code>&#39;$nested.column$&#39;</code> 语法:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line">User.findAll(&#123;</span><br><span class="line">    where: &#123;</span><br><span class="line">        <span class="string">'$Instruments.name$'</span>: &#123; [Op.iLike]: <span class="string">'%ooth%'</span> &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    include: [&#123;</span><br><span class="line">        model: Tool,</span><br><span class="line">        <span class="keyword">as</span>: <span class="string">'Instruments'</span></span><br><span class="line">    &#125;]</span><br><span class="line">&#125;).then(<span class="function"><span class="params">users</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="built_in">JSON</span>.stringify(users));</span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">      [&#123;</span></span><br><span class="line"><span class="comment">        "name": "John Doe",</span></span><br><span class="line"><span class="comment">        "id": 1,</span></span><br><span class="line"><span class="comment">        "createdAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">        "updatedAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">        "Instruments": [&#123;</span></span><br><span class="line"><span class="comment">          "name": "Toothpick",</span></span><br><span class="line"><span class="comment">          "id": 1,</span></span><br><span class="line"><span class="comment">          "createdAt": null,</span></span><br><span class="line"><span class="comment">          "updatedAt": null,</span></span><br><span class="line"><span class="comment">          "userId": 1</span></span><br><span class="line"><span class="comment">        &#125;]</span></span><br><span class="line"><span class="comment">      &#125;],</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">      [&#123;</span></span><br><span class="line"><span class="comment">        "name": "John Smith",</span></span><br><span class="line"><span class="comment">        "id": 2,</span></span><br><span class="line"><span class="comment">        "createdAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">        "updatedAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">        "Instruments": [&#123;</span></span><br><span class="line"><span class="comment">          "name": "Toothpick",</span></span><br><span class="line"><span class="comment">          "id": 1,</span></span><br><span class="line"><span class="comment">          "createdAt": null,</span></span><br><span class="line"><span class="comment">          "updatedAt": null,</span></span><br><span class="line"><span class="comment">          "userId": 1</span></span><br><span class="line"><span class="comment">        &#125;]</span></span><br><span class="line"><span class="comment">      &#125;],</span></span><br><span class="line"><span class="comment">    */</span></span><br></pre></td></tr></table></figure>

<h3 id="包括所有"><a href="#包括所有" class="headerlink" title="包括所有"></a>包括所有</h3><p>要包含所有属性,你可以使用 <code>all:true</code> 传递单个对象:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">User.findAll(&#123; <span class="attr">include</span>: [&#123; <span class="attr">all</span>: <span class="literal">true</span> &#125;] &#125;);</span><br></pre></td></tr></table></figure>

<h3 id="包括软删除的记录"><a href="#包括软删除的记录" class="headerlink" title="包括软删除的记录"></a>包括软删除的记录</h3><p>如果想要加载软删除的记录,可以通过将 <code>include.paranoid</code> 设置为 <code>false</code> 来实现</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">User.findAll(&#123;</span><br><span class="line">  include: [</span><br><span class="line">    &#123;</span><br><span class="line">      model: Tool,</span><br><span class="line">      where: &#123; <span class="attr">name</span>: &#123; [Op.like]: <span class="string">"%ooth%"</span> &#125; &#125;,</span><br><span class="line">      paranoid: <span class="literal">false</span>, <span class="comment">// query and loads the soft deleted records</span></span><br><span class="line">    &#125;,</span><br><span class="line">  ],</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="排序预加载关联"><a href="#排序预加载关联" class="headerlink" title="排序预加载关联"></a>排序预加载关联</h3><p>在一对多关系的情况下.</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">Company.findAll(&#123; <span class="attr">include</span>: [Division], <span class="attr">order</span>: [[Division, <span class="string">"name"</span>]] &#125;);</span><br><span class="line">Company.findAll(&#123; <span class="attr">include</span>: [Division], <span class="attr">order</span>: [[Division, <span class="string">"name"</span>, <span class="string">"DESC"</span>]] &#125;);</span><br><span class="line">Company.findAll(&#123;</span><br><span class="line">  include: [&#123; <span class="attr">model</span>: Division, <span class="attr">as</span>: <span class="string">"Div"</span> &#125;],</span><br><span class="line">  order: [[&#123; <span class="attr">model</span>: Division, <span class="attr">as</span>: <span class="string">"Div"</span> &#125;, <span class="string">"name"</span>]],</span><br><span class="line">&#125;);</span><br><span class="line">Company.findAll(&#123;</span><br><span class="line">  include: [&#123; <span class="attr">model</span>: Division, <span class="attr">as</span>: <span class="string">"Div"</span> &#125;],</span><br><span class="line">  order: [[&#123; <span class="attr">model</span>: Division, <span class="attr">as</span>: <span class="string">"Div"</span> &#125;, <span class="string">"name"</span>, <span class="string">"DESC"</span>]],</span><br><span class="line">&#125;);</span><br><span class="line">Company.findAll(&#123;</span><br><span class="line">  include: [&#123; <span class="attr">model</span>: Division, <span class="attr">include</span>: [Department] &#125;],</span><br><span class="line">  order: [[Division, Department, <span class="string">"name"</span>]],</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>在多对多关系的情况下,你还可以通过表中的属性进行排序.</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Company.findAll(&#123;</span><br><span class="line">  include: [&#123; <span class="attr">model</span>: Division, <span class="attr">include</span>: [Department] &#125;],</span><br><span class="line">  order: [[Division, DepartmentDivision, <span class="string">"name"</span>]],</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="嵌套预加载"><a href="#嵌套预加载" class="headerlink" title="嵌套预加载"></a>嵌套预加载</h3><p>你可以使用嵌套的预加载来加载相关模型的所有相关模型:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">User.findAll(&#123;</span><br><span class="line">  include: [</span><br><span class="line">    &#123;</span><br><span class="line">      model: Tool,</span><br><span class="line">      <span class="keyword">as</span>: <span class="string">"Instruments"</span>,</span><br><span class="line">      include: [</span><br><span class="line">        &#123;</span><br><span class="line">          model: Teacher,</span><br><span class="line">          include: [</span><br><span class="line">            <span class="comment">/* etc */</span></span><br><span class="line">          ],</span><br><span class="line">        &#125;,</span><br><span class="line">      ],</span><br><span class="line">    &#125;,</span><br><span class="line">  ],</span><br><span class="line">&#125;).then(<span class="function">(<span class="params">users</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="built_in">JSON</span>.stringify(users));</span><br><span class="line"></span><br><span class="line">  <span class="comment">/*</span></span><br><span class="line"><span class="comment">    [&#123;</span></span><br><span class="line"><span class="comment">      "name": "John Doe",</span></span><br><span class="line"><span class="comment">      "id": 1,</span></span><br><span class="line"><span class="comment">      "createdAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">      "updatedAt": "2013-03-20T20:31:45.000Z",</span></span><br><span class="line"><span class="comment">      "Instruments": [&#123; // 1:M and N:M association</span></span><br><span class="line"><span class="comment">        "name": "Toothpick",</span></span><br><span class="line"><span class="comment">        "id": 1,</span></span><br><span class="line"><span class="comment">        "createdAt": null,</span></span><br><span class="line"><span class="comment">        "updatedAt": null,</span></span><br><span class="line"><span class="comment">        "userId": 1,</span></span><br><span class="line"><span class="comment">        "Teacher": &#123; // 1:1 association</span></span><br><span class="line"><span class="comment">          "name": "Jimi Hendrix"</span></span><br><span class="line"><span class="comment">        &#125;</span></span><br><span class="line"><span class="comment">      &#125;]</span></span><br><span class="line"><span class="comment">    &#125;]</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>这将产生一个外连接. 但是,相关模型上的 <code>where</code> 语句将创建一个内部连接,并仅返回具有匹配子模型的实例. 要返回所有父实例,你应该添加 <code>required: false</code>.</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">User.findAll(&#123;</span><br><span class="line">  include: [</span><br><span class="line">    &#123;</span><br><span class="line">      model: Tool,</span><br><span class="line">      <span class="keyword">as</span>: <span class="string">"Instruments"</span>,</span><br><span class="line">      include: [</span><br><span class="line">        &#123;</span><br><span class="line">          model: Teacher,</span><br><span class="line">          where: &#123;</span><br><span class="line">            school: <span class="string">"Woodstock Music School"</span>,</span><br><span class="line">          &#125;,</span><br><span class="line">          required: <span class="literal">false</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">      ],</span><br><span class="line">    &#125;,</span><br><span class="line">  ],</span><br><span class="line">&#125;).then(<span class="function">(<span class="params">users</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">/* ... */</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>以上查询将返回所有用户及其所有乐器,但只会返回与 <code>Woodstock Music School</code> 相关的老师.</p>
<p>包括所有也支持嵌套加载:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">User.findAll(&#123; <span class="attr">include</span>: [&#123; <span class="attr">all</span>: <span class="literal">true</span>, <span class="attr">nested</span>: <span class="literal">true</span> &#125;] &#125;);</span><br></pre></td></tr></table></figure>

<h2 id="新增"><a href="#新增" class="headerlink" title="新增"></a>新增</h2><h3 id="字段限制"><a href="#字段限制" class="headerlink" title="字段限制"></a>字段限制</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">await</span> User.create(</span><br><span class="line">  &#123; <span class="attr">username</span>: <span class="string">"barfooz"</span>, <span class="attr">isAdmin</span>: <span class="literal">true</span> &#125;,</span><br><span class="line">  &#123; <span class="attr">fields</span>: [<span class="string">"username"</span>] &#125;</span><br><span class="line">);</span><br><span class="line"><span class="comment">// 只有username有效</span></span><br><span class="line"></span><br><span class="line">User.bulkCreate([&#123; <span class="attr">username</span>: <span class="string">"foo"</span> &#125;, &#123; <span class="attr">username</span>: <span class="string">"bar"</span>, <span class="attr">admin</span>: <span class="literal">true</span> &#125;], &#123;</span><br><span class="line">  fields: [<span class="string">"username"</span>],</span><br><span class="line">&#125;).then(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// admin 将不会被构建</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="新增单个"><a href="#新增单个" class="headerlink" title="新增单个"></a>新增单个</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// create</span></span><br><span class="line"><span class="keyword">this</span>.ctx.body = <span class="keyword">await</span> <span class="keyword">this</span>.ctx.model.User.create(&#123;</span><br><span class="line">  name: <span class="string">"哈哈哈"</span>,</span><br><span class="line">  age: <span class="number">12</span>,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="批量新增"><a href="#批量新增" class="headerlink" title="批量新增"></a>批量新增</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 批量新增 bulkCreate</span></span><br><span class="line"><span class="keyword">this</span>.ctx.body = <span class="keyword">await</span> <span class="keyword">this</span>.ctx.model.User.bulkCreate([</span><br><span class="line">  &#123;</span><br><span class="line">    name: <span class="string">"第一个"</span>,</span><br><span class="line">    age: <span class="number">15</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    name: <span class="string">"第二个"</span>,</span><br><span class="line">    age: <span class="number">15</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    name: <span class="string">"第三个"</span>,</span><br><span class="line">    age: <span class="number">15</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">]);</span><br></pre></td></tr></table></figure>

<h2 id="修改"><a href="#修改" class="headerlink" title="修改"></a>修改</h2><h3 id="字段限制-1"><a href="#字段限制-1" class="headerlink" title="字段限制"></a>字段限制</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">task.title = <span class="string">"foooo"</span>;</span><br><span class="line">task.description = <span class="string">"baaaaaar"</span>;</span><br><span class="line"><span class="keyword">await</span> task.save(&#123; <span class="attr">fields</span>: [<span class="string">"title"</span>] &#125;);</span><br><span class="line"><span class="comment">// title 现在将是 “foooo”,而 description 与以前一样</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用等效的 update 调用如下所示:</span></span><br><span class="line"><span class="keyword">await</span> task.update(</span><br><span class="line">  &#123; <span class="attr">title</span>: <span class="string">"foooo"</span>, <span class="attr">description</span>: <span class="string">"baaaaaar"</span> &#125;,</span><br><span class="line">  &#123; <span class="attr">fields</span>: [<span class="string">"title"</span>] &#125;</span><br><span class="line">);</span><br><span class="line"><span class="comment">//  title 现在将是 “foooo”,而 description 与以前一样</span></span><br></pre></td></tr></table></figure>

<h3 id="单个修改"><a href="#单个修改" class="headerlink" title="单个修改"></a>单个修改</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 找出当前记录</span></span><br><span class="line"><span class="keyword">const</span> user = <span class="keyword">await</span> <span class="keyword">this</span>.ctx.model.User.findByPk(<span class="number">1</span>);</span><br><span class="line"><span class="keyword">await</span> user.update(&#123;</span><br><span class="line">  name: <span class="string">"我被修改了"</span>,</span><br><span class="line">  age: <span class="number">30</span>,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="批量修改"><a href="#批量修改" class="headerlink" title="批量修改"></a>批量修改</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 批量修改</span></span><br><span class="line"><span class="keyword">await</span> <span class="keyword">this</span>.ctx.model.User.update(</span><br><span class="line">  &#123;</span><br><span class="line">    name: <span class="string">"批量修改"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="comment">// 条件</span></span><br><span class="line">    where: &#123;</span><br><span class="line">      name: <span class="string">"第一个"</span>,</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;</span><br><span class="line">);</span><br></pre></td></tr></table></figure>

<h3 id="递增"><a href="#递增" class="headerlink" title="递增"></a>递增</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 找出当前记录 increment</span></span><br><span class="line"><span class="keyword">const</span> user = <span class="keyword">await</span> <span class="keyword">this</span>.ctx.model.User.findByPk(<span class="number">2</span>);</span><br><span class="line"><span class="keyword">this</span>.ctx.body = <span class="keyword">await</span> user.increment(&#123;</span><br><span class="line">  age: <span class="number">3</span>, <span class="comment">// age每次递增3</span></span><br><span class="line">  other: <span class="number">2</span>, <span class="comment">// other每次递增2</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="递减"><a href="#递减" class="headerlink" title="递减"></a>递减</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 找出当前记录 decrement</span></span><br><span class="line"><span class="keyword">const</span> user = <span class="keyword">await</span> <span class="keyword">this</span>.ctx.model.User.findByPk(<span class="number">2</span>);</span><br><span class="line"><span class="keyword">this</span>.ctx.body = <span class="keyword">await</span> user.decrement(&#123;</span><br><span class="line">  age: <span class="number">3</span>, <span class="comment">// age每次递减3</span></span><br><span class="line">  other: <span class="number">2</span>, <span class="comment">// other每次递减2</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h2 id="删除"><a href="#删除" class="headerlink" title="删除"></a>删除</h2><h3 id="软删除"><a href="#软删除" class="headerlink" title="软删除"></a>软删除</h3><p>模型中配置</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 配置（重要）</span></span><br><span class="line"><span class="keyword">const</span> User = app.model.define(</span><br><span class="line">  <span class="string">"user"</span>,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="comment">/* bla */</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="comment">// 同时需要设置paranoid为true（此种模式下，删除数据时不会进行物理删除，而是设置deletedAt为当前时间</span></span><br><span class="line">    paranoid: <span class="literal">true</span>,</span><br><span class="line">  &#125;</span><br><span class="line">);</span><br></pre></td></tr></table></figure>

<h3 id="查询包括软删除内容"><a href="#查询包括软删除内容" class="headerlink" title="查询包括软删除内容"></a>查询包括软删除内容</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> user = <span class="keyword">await</span> ctx.model.User.findOne(&#123;</span><br><span class="line">  include: &#123;</span><br><span class="line">    model: ctx.model.Video,</span><br><span class="line">    <span class="comment">// 包括软删除</span></span><br><span class="line">    paranoid: <span class="literal">false</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  where: &#123;</span><br><span class="line">    id: <span class="number">33</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// 包括软删除</span></span><br><span class="line">  paranoid: <span class="literal">false</span>,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="彻底删除"><a href="#彻底删除" class="headerlink" title="彻底删除"></a>彻底删除</h3><p>如果 <code>paranoid</code> 选项为 true,则不会删除该对象,而将 <code>deletedAt</code> 列设置为当前时间戳. 要强制删除,可以将 <code>force: true</code> 传递给 destroy 调用:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">task.destroy(&#123; <span class="attr">force</span>: <span class="literal">true</span> &#125;);</span><br></pre></td></tr></table></figure>

<p>在 <code>paranoid</code> 模式下对象被软删除后,在强制删除旧实例之前,你将无法使用相同的主键创建新实例.</p>
<h3 id="恢复软删除的实例"><a href="#恢复软删除的实例" class="headerlink" title="恢复软删除的实例"></a>恢复软删除的实例</h3><p>如果你使用 <code>paranoid:true</code> 软删除了模型的实例,之后想要撤消删除,请使用 <code>restore</code> 方法:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 进行软删除...</span></span><br><span class="line">task.destroy();</span><br><span class="line"><span class="comment">// 恢复软删除...</span></span><br><span class="line">task.restore();</span><br></pre></td></tr></table></figure>

<h3 id="条件删除"><a href="#条件删除" class="headerlink" title="条件删除"></a>条件删除</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">await</span> <span class="keyword">this</span>.ctx.model.User.destroy(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    name: <span class="string">"批量修改"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="批量删除"><a href="#批量删除" class="headerlink" title="批量删除"></a>批量删除</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">await</span> <span class="keyword">this</span>.ctx.model.Post.destroy(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    id: posts,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h2 id="重载实例"><a href="#重载实例" class="headerlink" title="重载实例"></a>重载实例</h2><p>如果你需要让你的实例同步,你可以使用 <code>reload</code> 方法. 它将从数据库中获取当前数据,并覆盖调用该方法的模型的属性.</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">Person.findOne(&#123; <span class="attr">where</span>: &#123; <span class="attr">name</span>: <span class="string">"john"</span> &#125; &#125;).then(<span class="function">(<span class="params">person</span>) =&gt;</span> &#123;</span><br><span class="line">  person.name = <span class="string">"jane"</span>;</span><br><span class="line">  <span class="built_in">console</span>.log(person.name); <span class="comment">// 'jane'</span></span><br><span class="line"></span><br><span class="line">  person.reload().then(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(person.name); <span class="comment">// 'john'</span></span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h2 id="模型自定义方法"><a href="#模型自定义方法" class="headerlink" title="模型自定义方法"></a>模型自定义方法</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 模型</span></span><br><span class="line"><span class="comment">// 模型自定义方法</span></span><br><span class="line">topic_user.ceshi = <span class="function">(<span class="params">param</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">"模型自定义方法"</span>);</span><br><span class="line">  <span class="built_in">console</span>.log(param);</span><br><span class="line">  <span class="keyword">return</span> param;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 控制器</span></span><br><span class="line"><span class="keyword">await</span> <span class="keyword">this</span>.ctx.model.TopicUser.ceshi(<span class="number">123</span>);</span><br></pre></td></tr></table></figure>

<h2 id="Scopes-作用域（重点）"><a href="#Scopes-作用域（重点）" class="headerlink" title="Scopes - 作用域（重点）"></a>Scopes - 作用域（重点）</h2><p>作用域允许你定义常用查询,以便以后轻松使用. 作用域可以包括与常规查找器 <code>where</code>, <code>include</code>, <code>limit</code> 等所有相同的属性.</p>
<h3 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h3><p>作用域在模型定义中定义,可以是 finder 对象或返回 finder 对象的函数,除了默认作用域,该作用域只能是一个对象:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Project</span> <span class="keyword">extends</span> <span class="title">Model</span> </span>&#123;&#125;</span><br><span class="line">Project.init(&#123;</span><br><span class="line">  <span class="comment">// 属性</span></span><br><span class="line">&#125;, &#123;</span><br><span class="line">  defaultScope: &#123;</span><br><span class="line">    where: &#123;</span><br><span class="line">      active: <span class="literal">true</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  scopes: &#123;</span><br><span class="line">    deleted: &#123;</span><br><span class="line">      where: &#123;</span><br><span class="line">        deleted: <span class="literal">true</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    activeUsers: &#123;</span><br><span class="line">      include: [</span><br><span class="line">        &#123; <span class="attr">model</span>: User, <span class="attr">where</span>: &#123; <span class="attr">active</span>: <span class="literal">true</span> &#125;&#125;</span><br><span class="line">      ]</span><br><span class="line">    &#125;,</span><br><span class="line">    random () &#123;</span><br><span class="line">      <span class="keyword">return</span> &#123;</span><br><span class="line">        where: &#123;</span><br><span class="line">          someNumber: <span class="built_in">Math</span>.random()</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    accessLevel (value) &#123;</span><br><span class="line">      <span class="keyword">return</span> &#123;</span><br><span class="line">        where: &#123;</span><br><span class="line">          accessLevel: &#123;</span><br><span class="line">            [Op.gte]: value</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    sequelize,</span><br><span class="line">    modelName: <span class="string">'project'</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>通过调用 <code>addScope</code> 定义模型后,还可以添加作用域. 这对于具有包含的作用域特别有用,其中在定义其他模型时可能不会定义 include 中的模型.</p>
<p>始终应用默认作用域. 这意味着,通过上面的模型定义,<code>Project.findAll()</code> 将创建以下查询:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT * FROM projects WHERE active = <span class="literal">true</span></span><br></pre></td></tr></table></figure>

<p>可以通过调用 <code>.unscoped()</code>, <code>.scope(null)</code> 或通过调用另一个作用域来删除默认作用域:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Project.scope(<span class="string">'deleted'</span>).findAll(); <span class="comment">// 删除默认作用域</span></span><br><span class="line">SELECT * FROM projects WHERE deleted = <span class="literal">true</span></span><br></pre></td></tr></table></figure>

<p>还可以在作用域定义中包含作用域模型. 这让你避免重复 <code>include</code>,<code>attributes</code> 或 <code>where</code> 定义.</p>
<p>使用上面的例子,并在包含的用户模型中调用 <code>active</code> 作用域(而不是直接在该 include 对象中指定条件):</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">activeUsers: &#123;</span><br><span class="line">  include: [&#123; <span class="attr">model</span>: User.scope(<span class="string">"active"</span>) &#125;];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h3><p>通过在模型定义上调用 <code>.scope</code> 来应用作用域,传递一个或多个作用域的名称. <code>.scope</code> 返回一个全功能的模型实例,它具有所有常规的方法:<code>.findAll</code>,<code>.update</code>,<code>.count</code>,<code>.destroy</code>等等.你可以保存这个模型实例并稍后再次使用:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> DeletedProjects = Project.scope(<span class="string">"deleted"</span>);</span><br><span class="line"></span><br><span class="line">DeletedProjects.findAll();</span><br><span class="line"><span class="comment">// 过一段时间</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 让我们再次寻找被删除的项目！</span></span><br><span class="line">DeletedProjects.findAll();</span><br></pre></td></tr></table></figure>

<p>作用域适用于 <code>.find</code>, <code>.findAll</code>, <code>.count</code>, <code>.update</code>, <code>.increment</code> 和 <code>.destroy</code>.</p>
<p>可以通过两种方式调用作为函数的作用域. 如果作用域没有任何参数,它可以正常调用. 如果作用域采用参数,则传递一个对象:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Project.scope(<span class="string">'random'</span>, &#123; <span class="attr">method</span>: [<span class="string">'accessLevel'</span>, <span class="number">19</span>]&#125;).findAll();</span><br><span class="line">SELECT * FROM projects WHERE someNumber = <span class="number">42</span> AND accessLevel &gt;= <span class="number">19</span></span><br></pre></td></tr></table></figure>

<h3 id="合并"><a href="#合并" class="headerlink" title="合并"></a>合并</h3><p>通过将作用域数组传递到 <code>.scope</code> 或通过将作用域作为连续参数传递,可以同时应用多个作用域.</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 这两个是等价的</span></span><br><span class="line">Project.scope(<span class="string">'deleted'</span>, <span class="string">'activeUsers'</span>).findAll();</span><br><span class="line">Project.scope([<span class="string">'deleted'</span>, <span class="string">'activeUsers'</span>]).findAll();</span><br><span class="line">SELECT * FROM projects</span><br><span class="line">INNER JOIN users ON projects.userId = users.id</span><br><span class="line">WHERE projects.deleted = <span class="literal">true</span></span><br><span class="line">AND users.active = <span class="literal">true</span></span><br></pre></td></tr></table></figure>

<p>如果要将其他作用域与默认作用域一起应用,请将键 <code>defaultScope</code> 传递给 <code>.scope</code>:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Project.scope(<span class="string">'defaultScope'</span>, <span class="string">'deleted'</span>).findAll();</span><br><span class="line">SELECT * FROM projects WHERE active = <span class="literal">true</span> AND deleted = <span class="literal">true</span></span><br></pre></td></tr></table></figure>

<p>当调用多个作用域时,后续作用域的键将覆盖以前的作用域(类似于 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign" target="_blank" rel="noopener">Object.assign</a>),除了<code>where</code>和<code>include</code>,它们将被合并. 考虑两个作用域:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  scope1: &#123;</span><br><span class="line">    where: &#123;</span><br><span class="line">      firstName: <span class="string">'bob'</span>,</span><br><span class="line">      age: &#123;</span><br><span class="line">        [Op.gt]: <span class="number">20</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    limit: <span class="number">2</span></span><br><span class="line">  &#125;,</span><br><span class="line">  scope2: &#123;</span><br><span class="line">    where: &#123;</span><br><span class="line">      age: &#123;</span><br><span class="line">        [Op.gt]: <span class="number">30</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    limit: <span class="number">10</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>调用 <code>.scope(&#39;scope1&#39;, &#39;scope2&#39;)</code> 将产生以下查询</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">WHERE firstName = <span class="string">'bob'</span> AND age &gt; <span class="number">30</span> LIMIT <span class="number">10</span></span><br></pre></td></tr></table></figure>

<p>注意 <code>scope2</code> 将覆盖 <code>limit</code> 和 <code>age</code>,而 <code>firstName</code> 被保留. <code>limit</code>,<code>offset</code>,<code>order</code>,<code>paranoid</code>,<code>lock</code>和<code>raw</code>字段被覆盖,而<code>where</code>被浅层合并(意味着相同的键将被覆盖). <code>include</code> 的合并策略将在后面讨论.</p>
<p>请注意,多个应用作用域的 <code>attributes</code> 键以这样的方式合并,即始终保留 <code>attributes.exclude</code>. 这允许合并多个作用域,并且永远不会泄漏最终作用域内的敏感字段.</p>
<p>将查找对象直接传递给作用域模型上的<code>findAll</code>(和类似的查找程序)时,适用相同的合并逻辑:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Project.scope(<span class="string">'deleted'</span>).findAll(&#123;</span><br><span class="line">  where: &#123;</span><br><span class="line">    firstName: <span class="string">'john'</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line">WHERE deleted = <span class="literal">true</span> AND firstName = <span class="string">'john'</span></span><br></pre></td></tr></table></figure>

<p>这里的 <code>deleted</code> 作用域与 finder 合并. 如果我们要将 <code>where: { firstName: &#39;john&#39;, deleted: false }</code> 传递给 finder,那么 <code>deleted</code> 作用域将被覆盖.</p>
<h4 id="合并-include"><a href="#合并-include" class="headerlink" title="合并 include"></a>合并 include</h4><p>Include 是根据包含的模型递归合并的. 这是一个非常强大的合并,在 v5 上添加,并通过示例更好地理解.</p>
<p>考虑四种模型:Foo,Bar,Baz 和 Qux,具有如下多种关联:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Foo</span> <span class="keyword">extends</span> <span class="title">Model</span> </span>&#123;&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Bar</span> <span class="keyword">extends</span> <span class="title">Model</span> </span>&#123;&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Baz</span> <span class="keyword">extends</span> <span class="title">Model</span> </span>&#123;&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Qux</span> <span class="keyword">extends</span> <span class="title">Model</span> </span>&#123;&#125;</span><br><span class="line">Foo.init(&#123; <span class="attr">name</span>: Sequelize.STRING &#125;, &#123; sequelize &#125;);</span><br><span class="line">Bar.init(&#123; <span class="attr">name</span>: Sequelize.STRING &#125;, &#123; sequelize &#125;);</span><br><span class="line">Baz.init(&#123; <span class="attr">name</span>: Sequelize.STRING &#125;, &#123; sequelize &#125;);</span><br><span class="line">Qux.init(&#123; <span class="attr">name</span>: Sequelize.STRING &#125;, &#123; sequelize &#125;);</span><br><span class="line">Foo.hasMany(Bar, &#123; <span class="attr">foreignKey</span>: <span class="string">"fooId"</span> &#125;);</span><br><span class="line">Bar.hasMany(Baz, &#123; <span class="attr">foreignKey</span>: <span class="string">"barId"</span> &#125;);</span><br><span class="line">Baz.hasMany(Qux, &#123; <span class="attr">foreignKey</span>: <span class="string">"bazId"</span> &#125;);</span><br></pre></td></tr></table></figure>

<p>现在,考虑 Foo 上定义的以下四个作用域:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  includeEverything: &#123;</span><br><span class="line">    include: &#123;</span><br><span class="line">      model: <span class="keyword">this</span>.Bar,</span><br><span class="line">      include: [&#123;</span><br><span class="line">        model: <span class="keyword">this</span>.Baz,</span><br><span class="line">        include: <span class="keyword">this</span>.Qux</span><br><span class="line">      &#125;]</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  limitedBars: &#123;</span><br><span class="line">    include: [&#123;</span><br><span class="line">      model: <span class="keyword">this</span>.Bar,</span><br><span class="line">      limit: <span class="number">2</span></span><br><span class="line">    &#125;]</span><br><span class="line">  &#125;,</span><br><span class="line">  limitedBazs: &#123;</span><br><span class="line">    include: [&#123;</span><br><span class="line">      model: <span class="keyword">this</span>.Bar,</span><br><span class="line">      include: [&#123;</span><br><span class="line">        model: <span class="keyword">this</span>.Baz,</span><br><span class="line">        limit: <span class="number">2</span></span><br><span class="line">      &#125;]</span><br><span class="line">    &#125;]</span><br><span class="line">  &#125;,</span><br><span class="line">  excludeBazName: &#123;</span><br><span class="line">    include: [&#123;</span><br><span class="line">      model: <span class="keyword">this</span>.Bar,</span><br><span class="line">      include: [&#123;</span><br><span class="line">        model: <span class="keyword">this</span>.Baz,</span><br><span class="line">        attributes: &#123;</span><br><span class="line">          exclude: [<span class="string">'name'</span>]</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;]</span><br><span class="line">    &#125;]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这四个作用域可以很容易地深度合并,例如通过调用 <code>Foo.scope(&#39;includeEverything&#39;, &#39;limitedBars&#39;, &#39;limitedBazs&#39;, &#39;excludeBazName&#39;).findAll()</code>,这完全等同于调用以下内容:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">Foo.findAll(&#123;</span><br><span class="line">  include: &#123;</span><br><span class="line">    model: <span class="keyword">this</span>.Bar,</span><br><span class="line">    limit: <span class="number">2</span>,</span><br><span class="line">    include: [</span><br><span class="line">      &#123;</span><br><span class="line">        model: <span class="keyword">this</span>.Baz,</span><br><span class="line">        limit: <span class="number">2</span>,</span><br><span class="line">        attributes: &#123;</span><br><span class="line">          exclude: [<span class="string">"name"</span>],</span><br><span class="line">        &#125;,</span><br><span class="line">        include: <span class="keyword">this</span>.Qux,</span><br><span class="line">      &#125;,</span><br><span class="line">    ],</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>观察四个作用域如何合并为一个. 根据所包含的模型合并作用域的 include. 如果一个作用域包括模型 A 而另一个作用域包括模型 B,则合并结果将包括模型 A 和 B.另一方面,如果两个作用域包括相同的模型 A,但具有不同的参数(例如嵌套 include 或其他属性) ,这些将以递归方式合并,如上所示.</p>
<p>无论应用于作用域的顺序如何,上面说明的合并都以完全相同的方式工作. 如果某个参数由两个不同的作用域设置,那么只会该顺序产生差异 - 这不是上述示例的情况,因为每个作用域都做了不同的事情.</p>
<p>这种合并策略的工作方式与传递给<code>.findAll</code>,<code>.findOne</code>等的参数完全相同.</p>
<h3 id="关联"><a href="#关联" class="headerlink" title="关联"></a>关联</h3><p>Sequelize 与关联有两个不同但相关的作用域概念. 差异是微妙但重要的:</p>
<ul>
<li><strong>关联作用域</strong> 允许你在获取和设置关联时指定默认属性 - 在实现多态关联时很有用. 当使用<code>get</code>,<code>set</code>,<code>add</code>和<code>create</code>相关联的模型函数时,这个作用域仅在两个模型之间的关联上被调用</li>
<li><strong>关联模型上的作用域</strong> 允许你在获取关联时应用默认和其他作用域,并允许你在创建关联时传递作用域模型. 这些作用域都适用于模型上的常规查找和通过关联查找.</li>
</ul>
<p>举个例子,思考模型 Post 和 Comment. Comment 与其他几个模型(图像,视频等)相关联,Comment 和其他模型之间的关联是多态的,这意味着除了外键 <code>commentable_id</code> 之外,注释还存储一个<code>commentable</code>列.</p>
<p>可以使用 association scope 来实现多态关联:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>.Post.hasMany(<span class="keyword">this</span>.Comment, &#123;</span><br><span class="line">  foreignKey: <span class="string">"commentable_id"</span>,</span><br><span class="line">  scope: &#123;</span><br><span class="line">    commentable: <span class="string">"post"</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>当调用 <code>post.getComments()</code> 时,这将自动添加 <code>WHERE commentable = &#39;post&#39;</code>. 类似地,当向帖子添加新的注释时,<code>commentable</code> 会自动设置为 <code>&#39;post&#39;</code>. 关联作用域是为了存活于后台,没有程序员不必担心 - 它不能被禁用. 有关更完整的多态性示例,请参阅 <a href="https://itfun.tv/documents/272#scopes" target="_blank" rel="noopener">关联作用域</a></p>
<p>那么考虑那个 Post 的默认作用域只显示活动的帖子:<code>where: { active: true }</code>. 该作用域存在于相关联的模型(Post)上,而不是像<code>commentable</code> 作用域那样在关联上. 就像在调用<code>Post.findAll()</code> 时一样应用默认作用域,当调用 <code>User.getPosts()</code> 时,它也会被应用 - 这只会返回该用户的活动帖子.</p>
<p>要禁用默认作用域,将 <code>scope: null</code> 传递给 getter: <code>User.getPosts({ scope: null })</code>. 同样,如果要应用其他作用域,请像这样:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">User.getPosts(&#123; <span class="attr">scope</span>: [<span class="string">"scope1"</span>, <span class="string">"scope2"</span>] &#125;);</span><br></pre></td></tr></table></figure>

<p>如果要为关联模型上的作用域创建快捷方式,可以将作用域模型传递给关联. 考虑一个快捷方式来获取用户所有已删除的帖子:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Post</span> <span class="keyword">extends</span> <span class="title">Model</span> </span>&#123;&#125;</span><br><span class="line">Post.init(attributes, &#123;</span><br><span class="line">  defaultScope: &#123;</span><br><span class="line">    where: &#123;</span><br><span class="line">      active: <span class="literal">true</span>,</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">  scopes: &#123;</span><br><span class="line">    deleted: &#123;</span><br><span class="line">      where: &#123;</span><br><span class="line">        deleted: <span class="literal">true</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">  sequelize,</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">User.hasMany(Post); <span class="comment">// 常规 getPosts 关联</span></span><br><span class="line">User.hasMany(Post.scope(<span class="string">"deleted"</span>), &#123; <span class="attr">as</span>: <span class="string">"deletedPosts"</span> &#125;);</span><br><span class="line">User.getPosts(); <span class="comment">// WHERE active = true</span></span><br><span class="line">User.getDeletedPosts(); <span class="comment">// WHERE deleted = true</span></span><br></pre></td></tr></table></figure>

<h1 id="扩展"><a href="#扩展" class="headerlink" title="扩展"></a>扩展</h1><p>extend/helper.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app/extend/helper.js</span></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="comment">// 扩展一个格式日期的方法</span></span><br><span class="line">  formatTime(val) &#123;</span><br><span class="line">    <span class="keyword">let</span> d = <span class="keyword">new</span> <span class="built_in">Date</span>(val * <span class="number">1000</span>);</span><br><span class="line">    <span class="keyword">return</span> d.getFullYear();</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>模板中调用</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">%=helper.formatTime(dateline)%</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>其他地方调用</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>.ctx.helper.formatTime(dateline);</span><br></pre></td></tr></table></figure>

<h1 id="中间件"><a href="#中间件" class="headerlink" title="中间件"></a>中间件</h1><h2 id="1-定义"><a href="#1-定义" class="headerlink" title="1. 定义"></a>1. 定义</h2><p>app/middleware/getIp.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">options: 中间件的配置项，框架会将 app.config[$&#123;middlewareName&#125;] 传递进来。</span></span><br><span class="line"><span class="comment">app: 当前应用 Application 的实例。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function">(<span class="params">option, app</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 返回一个异步的方法</span></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> (<span class="params">ctx, next</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 通过option传入额外参数</span></span><br><span class="line">    <span class="built_in">console</span>.log(option);</span><br><span class="line">    <span class="built_in">console</span>.log(ctx.request.ip);</span><br><span class="line">    <span class="keyword">await</span> next();</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h2 id="2-配置"><a href="#2-配置" class="headerlink" title="2. 配置"></a>2. 配置</h2><p>config/config.default.js（配置全局中间件，所有路由都会调用）</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="params">appInfo</span> =&gt;</span> &#123;</span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 配置全局中间件</span></span><br><span class="line">    config.middleware = [<span class="string">'getIp'</span>]; <span class="comment">// 注意驼峰式写法，如果中间件是a_bc.js，则要写成aBc</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 配置中间件参数</span></span><br><span class="line">    config.getIp = &#123;</span><br><span class="line">        ceshi: <span class="number">123</span>,</span><br><span class="line">        <span class="comment">// 通用配置（以下是重点）</span></span><br><span class="line">        enable:<span class="literal">true</span>, <span class="comment">// 控制中间件是否开启。</span></span><br><span class="line">        match:<span class="string">'/news'</span>, <span class="comment">// 设置只有符合某些规则的请求才会经过这个中间件（匹配路由）</span></span><br><span class="line">        ignore:<span class="string">'/shop'</span> <span class="comment">// 设置符合某些规则的请求不经过这个中间件。</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">        注意：</span></span><br><span class="line"><span class="comment">        1. match 和 ignore 不允许同时配置</span></span><br><span class="line"><span class="comment">        2. 例如：match:'/news'，只要包含/news的任何页面都生效</span></span><br><span class="line"><span class="comment">        **/</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// match 和 ignore 支持多种类型的配置方式：字符串、正则、函数（推荐）</span></span><br><span class="line">        match(ctx) &#123;</span><br><span class="line">          <span class="comment">// 只有 ios 设备才开启</span></span><br><span class="line">          <span class="keyword">const</span> reg = <span class="regexp">/iphone|ipad|ipod/i</span>;</span><br><span class="line">          <span class="keyword">return</span> reg.test(ctx.get(<span class="string">'user-agent'</span>));</span><br><span class="line">        &#125;,</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    ...</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h2 id="3-使用"><a href="#3-使用" class="headerlink" title="3. 使用"></a>3. 使用</h2><h3 id="路由中使用"><a href="#路由中使用" class="headerlink" title="路由中使用"></a>路由中使用</h3><p>app/router.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = <span class="function">(<span class="params">app</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 局部中间件（如果只需要局部调用，则不需要在config.default.js中配置）</span></span><br><span class="line">  router.get(</span><br><span class="line">    <span class="string">"/admin/:id"</span>,</span><br><span class="line">    app.middleware.getIp(&#123;</span><br><span class="line">      ceshi: <span class="string">"我是admin"</span>,</span><br><span class="line">    &#125;),</span><br><span class="line">    controller.admin.index</span><br><span class="line">  );</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h3 id="使用-Koa-的中间件（gzip-压缩）"><a href="#使用-Koa-的中间件（gzip-压缩）" class="headerlink" title="使用 Koa 的中间件（gzip 压缩）"></a>使用 Koa 的中间件（gzip 压缩）</h3><p>大大提高网站的访问速度（非常有效）</p>
<p>以 <a href="https://github.com/koajs/compress" target="_blank" rel="noopener">koa-compress</a> 为例，在 Koa 中使用时：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> koa = <span class="built_in">require</span>(<span class="string">"koa"</span>);</span><br><span class="line"><span class="keyword">const</span> compress = <span class="built_in">require</span>(<span class="string">"koa-compress"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> app = koa();</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> options = &#123; <span class="attr">threshold</span>: <span class="number">2048</span> &#125;;</span><br><span class="line">app.use(compress(options));</span><br></pre></td></tr></table></figure>

<p>我们按照框架的规范来在应用中加载这个 Koa 的中间件：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app/middleware/compress.js</span></span><br><span class="line"><span class="comment">// koa-compress 暴露的接口(`(options) =&gt; middleware`)和框架对中间件要求一致</span></span><br><span class="line"><span class="built_in">module</span>.exports = <span class="built_in">require</span>(<span class="string">"koa-compress"</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// config/config.default.js</span></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  middleware: [<span class="string">"compress"</span>],</span><br><span class="line">  compress: &#123;</span><br><span class="line">    threshold: <span class="number">2048</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h1 id="表单提交"><a href="#表单提交" class="headerlink" title="表单提交"></a>表单提交</h1><h2 id="post"><a href="#post" class="headerlink" title="post"></a>post</h2><p>app/controller/home.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> addInput(ctx) &#123;</span><br><span class="line">    <span class="keyword">await</span> ctx.render(<span class="string">'post'</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> add(ctx) &#123;</span><br><span class="line">    <span class="comment">// 通过ctx.request.body获取post提交数据</span></span><br><span class="line">    <span class="built_in">console</span>.log(ctx.request.body);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>app/view/post.html</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">需要定义：?_csrf=&lt;%=ctx.csrf%&gt;</span></span><br><span class="line"><span class="comment">--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">"/add?_csrf=&lt;%=ctx.csrf%&gt;"</span> <span class="attr">method</span>=<span class="string">"post"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">name</span>=<span class="string">"username"</span> <span class="attr">id</span>=<span class="string">"username"</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"password"</span> <span class="attr">name</span>=<span class="string">"password"</span> <span class="attr">id</span>=<span class="string">"password"</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"submit"</span> <span class="attr">value</span>=<span class="string">"提交"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>app/router.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">router.get(<span class="string">"/post"</span>, controller.home.addInput);</span><br><span class="line">router.post(<span class="string">"/add"</span>, controller.home.add);</span><br></pre></td></tr></table></figure>

<h1 id="cookie"><a href="#cookie" class="headerlink" title="cookie"></a>cookie</h1><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1.设置</span></span><br><span class="line">ctx.cookies.set(<span class="string">"username"</span>, <span class="string">"ceshi"</span>);</span><br><span class="line"><span class="comment">// 2.获取</span></span><br><span class="line">ctx.cookies.get(<span class="string">"username"</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 3.设置中文(加密操作 encrypt: true)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 4.设置（其他参数配置）</span></span><br><span class="line">ctx.cookies.set(<span class="string">"username"</span>, <span class="string">"ceshi"</span>, &#123;</span><br><span class="line">  maxAge: <span class="number">1000</span> * <span class="number">3600</span> * <span class="number">24</span>, <span class="comment">// 存储24小时，单位毫秒，关闭浏览器cookie还存在</span></span><br><span class="line">  httpOnly: <span class="literal">true</span>, <span class="comment">// 设置键值对是否可以被 js 访问，默认为 true，不允许被 js 访问。</span></span><br><span class="line">  signed: <span class="literal">true</span>, <span class="comment">// 签名，防止用户前台修改</span></span><br><span class="line">  encrypt: <span class="literal">true</span>, <span class="comment">// 加密，注意：get获取时需要解密</span></span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// 5.获取时解密</span></span><br><span class="line">ctx.cookies.get(<span class="string">"username"</span>, &#123;</span><br><span class="line">  encrypt: <span class="literal">true</span>,</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 6.清除cookie</span></span><br><span class="line">ctx.cookies.set(<span class="string">"username"</span>, <span class="literal">null</span>);</span><br></pre></td></tr></table></figure>

<h1 id="session"><a href="#session" class="headerlink" title="session"></a>session</h1><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1.设置</span></span><br><span class="line">ctx.session.username = <span class="string">"测试"</span>;</span><br><span class="line"><span class="comment">// 2.获取</span></span><br><span class="line">ctx.session.username;</span><br><span class="line"><span class="comment">// 3.默认配置（全局配置，config/config.default.js）</span></span><br><span class="line">exports.session = &#123;</span><br><span class="line">  key: <span class="string">"EGG_SESS"</span>, <span class="comment">// 设置cookies的key值</span></span><br><span class="line">  maxAge: <span class="number">24</span> * <span class="number">3600</span> * <span class="number">1000</span>, <span class="comment">// 1 天，过期时间</span></span><br><span class="line">  httpOnly: <span class="literal">true</span>, <span class="comment">// 设置键值对是否可以被 js 访问，默认为 true，不允许被 js 访问。</span></span><br><span class="line">  encrypt: <span class="literal">true</span>, <span class="comment">// 加密</span></span><br><span class="line">  renew: <span class="literal">true</span>, <span class="comment">// 每次刷新页面都会被延期</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">// 4.动态配置</span></span><br><span class="line">ctx.session.maxAge = <span class="number">5000</span>; <span class="comment">// 5秒的过期时间</span></span><br><span class="line">ctx.session.username = <span class="string">"测试"</span>;</span><br><span class="line"><span class="comment">// 5.清空session</span></span><br><span class="line">ctx.session.username = <span class="literal">null</span>;</span><br></pre></td></tr></table></figure>

<h1 id="定时任务"><a href="#定时任务" class="headerlink" title="定时任务"></a>定时任务</h1><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app/schedule/ceshi.js</span></span><br><span class="line"><span class="keyword">var</span> i = <span class="number">1</span>;</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="comment">// 设置定时任务的执行间隔等配置</span></span><br><span class="line">  schedule: &#123;</span><br><span class="line">    interval: <span class="string">"5s"</span>, <span class="comment">// 每5秒执行一次</span></span><br><span class="line">    type: <span class="string">"all"</span>, <span class="comment">// 指定所有的 worker 都需要执行</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// 任务</span></span><br><span class="line">  <span class="keyword">async</span> task(ctx) &#123;</span><br><span class="line">    ++i;</span><br><span class="line">    <span class="built_in">console</span>.log(i);</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h1 id="API"><a href="#API" class="headerlink" title="API"></a>API</h1><h2 id="1-context"><a href="#1-context" class="headerlink" title="1. context"></a>1. context</h2><h3 id="curl"><a href="#curl" class="headerlink" title="curl"></a>curl</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> ceshi() &#123;</span><br><span class="line">    <span class="comment">// 通过ctx中的curl方法获取数据</span></span><br><span class="line">    <span class="keyword">let</span> r = <span class="keyword">await</span> <span class="keyword">this</span>.ctx.curl(<span class="string">'http://www.phonegap100.com/appapi.php?a=getPortalList&amp;catid=20&amp;page=1'</span>);</span><br><span class="line">    <span class="comment">// 将buffer类型数据转为json类型</span></span><br><span class="line">    <span class="keyword">let</span> &#123; result &#125; = <span class="built_in">JSON</span>.parse(r.data)</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="常用插件"><a href="#常用插件" class="headerlink" title="常用插件"></a>常用插件</h1><h2 id="缓存"><a href="#缓存" class="headerlink" title="缓存"></a>缓存</h2><p><a href="https://www.npmjs.com/package/egg-cache" target="_blank" rel="noopener">https://www.npmjs.com/package/egg-cache</a><br><a href="https://www.npmjs.com/package/egg-redis" target="_blank" rel="noopener">https://www.npmjs.com/package/egg-redis</a></p>
<h2 id="验证"><a href="#验证" class="headerlink" title="验证"></a>验证</h2><p><a href="https://github.com/temool/egg-validate-plus" target="_blank" rel="noopener">https://github.com/temool/egg-validate-plus</a></p>
<h2 id="加密"><a href="#加密" class="headerlink" title="加密"></a>加密</h2><p><a href="https://www.npmjs.com/package/egg-jwt" target="_blank" rel="noopener">https://www.npmjs.com/package/egg-jwt</a></p>
<p>前端访问：header 头添加：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Authorization:"Bearer token值"</span></span><br><span class="line">Authorization: <span class="string">"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6MTIzLCJpYXQiOjE1NzkxOTQxNTN9.Ml5B02ZPfYo78QwJic-Jdp2LUi2_AU0RGNgPhhJH--o"</span>;</span><br></pre></td></tr></table></figure>

      
      <!-- reward -->
      
      <div id="reward-btn">
        Donate
      </div>
      
    </div>
    
    
      <!-- copyright -->
      
        <div class="declare">
          <ul class="post-copyright">
            <li>
              <i class="ri-copyright-line"></i>
              <strong>Copyright： </strong>
              Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
            </li>
          </ul>
        </div>
        
    <footer class="article-footer">
      
          
<div class="share-btn">
      <span class="share-sns share-outer">
        <i class="ri-share-forward-line"></i>
        分享
      </span>
      <div class="share-wrap">
        <i class="arrow"></i>
        <div class="share-icons">
          
          <a class="weibo share-sns" href="javascript:;" data-type="weibo">
            <i class="ri-weibo-fill"></i>
          </a>
          <a class="weixin share-sns wxFab" href="javascript:;" data-type="weixin">
            <i class="ri-wechat-fill"></i>
          </a>
          <a class="qq share-sns" href="javascript:;" data-type="qq">
            <i class="ri-qq-fill"></i>
          </a>
          <a class="douban share-sns" href="javascript:;" data-type="douban">
            <i class="ri-douban-line"></i>
          </a>
          <!-- <a class="qzone share-sns" href="javascript:;" data-type="qzone">
            <i class="icon icon-qzone"></i>
          </a> -->
          
          <a class="facebook share-sns" href="javascript:;" data-type="facebook">
            <i class="ri-facebook-circle-fill"></i>
          </a>
          <a class="twitter share-sns" href="javascript:;" data-type="twitter">
            <i class="ri-twitter-fill"></i>
          </a>
          <a class="google share-sns" href="javascript:;" data-type="google">
            <i class="ri-google-fill"></i>
          </a>
        </div>
      </div>
</div>

<div class="wx-share-modal">
    <a class="modal-close" href="javascript:;"><i class="ri-close-circle-line"></i></a>
    <p>扫一扫，分享到微信</p>
    <div class="wx-qrcode">
      <img src="//api.qrserver.com/v1/create-qr-code/?size=150x150&data=http://yoursite.com/2020/04/17/hello-egg/" alt="微信分享二维码">
    </div>
</div>

<div id="share-mask"></div>
      
      

    </footer>

  </div>

  
  
  <nav class="article-nav">
    
      <a href="/2020/04/18/egg-%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/" class="article-nav-link">
        <strong class="article-nav-caption">上一篇</strong>
        <div class="article-nav-title">
          
            egg-使用教程
          
        </div>
      </a>
    
    
      <a href="/2020/04/17/hello-world/" class="article-nav-link">
        <strong class="article-nav-caption">下一篇</strong>
        <div class="article-nav-title">Hello World</div>
      </a>
    
  </nav>


  

  
  
<!-- valine评论 -->
<div id="vcomments-box">
    <div id="vcomments">
    </div>
</div>
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src='https://cdn.jsdelivr.net/npm/valine@1.3.10/dist/Valine.min.js'></script>
<script>
    new Valine({
        el: '#vcomments',
        app_id: '',
        app_key: '',
        path: window.location.pathname,
        notify: 'false',
        verify: 'false',
        avatar: 'monsterid',
        placeholder: '给我的文章加点评论吧~',
        recordIP: true
    });
    const infoEle = document.querySelector('#vcomments .info');
    if (infoEle && infoEle.childNodes && infoEle.childNodes.length > 0) {
        infoEle.childNodes.forEach(function (item) {
            item.parentNode.removeChild(item);
        });
    }
</script>
<style>
    #vcomments-box {
        padding: 5px 30px;
    }

    @media screen and (max-width: 800px) {
        #vcomments-box {
            padding: 5px 0px;
        }
    }

    #vcomments-box #vcomments {
        background-color: #fff;
    }

    .v .vlist .vcard .vh {
        padding-right: 20px;
    }

    .v .vlist .vcard {
        padding-left: 10px;
    }
</style>

  

  
  
  
  
  

</article>
</section>
      <footer class="footer">
  <div class="outer">
    <ul>
      <li>
        Copyrights &copy;
        2015-2020
        <i class="ri-heart-fill heart_icon"></i> 钱开致
      </li>
    </ul>
    <ul>
      <li>
        
        
        
        Powered by <a href="https://hexo.io" target="_blank">Hexo</a>
        <span class="division">|</span>
        Theme - <a href="https://github.com/Shen-Yu/hexo-theme-ayer" target="_blank">Ayer</a>
        
      </li>
    </ul>
    <ul>
      <li>
        
        
        <span>
  <span><i class="ri-user-3-fill"></i>Visitors:<span id="busuanzi_value_site_uv"></span></s>
  <span class="division">|</span>
  <span><i class="ri-eye-fill"></i>Views:<span id="busuanzi_value_page_pv"></span></span>
</span>
        
      </li>
    </ul>
    <ul>
      
    </ul>
    <ul>
      <li>
        <!-- cnzz统计 -->
        
        <script type="text/javascript" src='https://s9.cnzz.com/z_stat.php?id=1278069914&amp;web_id=1278069914'></script>
        
      </li>
    </ul>
  </div>
</footer>
      <div class="float_btns">
        <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>

<div class="todark" id="todark">
  <i class="ri-moon-line"></i>
</div>

      </div>
    </main>
    <aside class="sidebar on">
      <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/"><img src="/images/ayer-side.svg" alt="simplett"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/archives">归档</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/categories">分类</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags">标签</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/%E6%97%85%E8%A1%8C/">旅行</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="http://shenyu-vip.lofter.com" target="_blank" rel="noopener">摄影</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/2019/about">关于我</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="Search">
        <i class="ri-search-line"></i>
      </a>
      
      
      <a class="nav-item-link" target="_blank" href="/atom.xml" title="RSS Feed">
        <i class="ri-rss-line"></i>
      </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
    </aside>
    <script>
      if (window.matchMedia("(max-width: 768px)").matches) {
        document.querySelector('.content').classList.remove('on');
        document.querySelector('.sidebar').classList.remove('on');
      }
    </script>
    <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯咖啡吧~</p>
  <div class="reward-box">
    
    <div class="reward-item">
      <img class="reward-img" src="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/img/alipay.jpg">
      <span class="reward-type">支付宝</span>
    </div>
    
    
    <div class="reward-item">
      <img class="reward-img" src="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/img/wechat.jpg">
      <span class="reward-type">微信</span>
    </div>
    
  </div>
</div>
    
<script src="/js/jquery-2.0.3.min.js"></script>


<script src="/js/lazyload.min.js"></script>


<script>
  try {
    var typed = new Typed("#subtitle", {
      strings: ['面朝大海，春暖花开', '愿你一生努力，一生被爱', '想要的都拥有，得不到的都释怀'],
      startDelay: 0,
      typeSpeed: 200,
      loop: true,
      backSpeed: 100,
      showCursor: true
    });
  } catch (err) {
  }

</script>




<script src="/js/tocbot.min.js"></script>

<script>
  // Tocbot_v4.7.0  http://tscanlin.github.io/tocbot/
  tocbot.init({
    tocSelector: '.tocbot',
    contentSelector: '.article-entry',
    headingSelector: 'h1, h2, h3, h4, h5, h6',
    hasInnerContainers: true,
    scrollSmooth: true,
    scrollContainer: 'main',
    positionFixedSelector: '.tocbot',
    positionFixedClass: 'is-position-fixed',
    fixedSidebarOffset: 'auto'
  });
</script>



<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css">
<script src="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/js/jquery.justifiedGallery.min.js"></script>

<script src="/dist/main.js"></script>



<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.min.css">
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script>





<script src="/js/busuanzi-2.3.pure.min.js"></script>



<script type="text/javascript" src="https://js.users.51.la/20544303.js"></script>


<!-- 复制 -->

  
<link rel="stylesheet" href="/css/clipboard.css">

  <script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
  function wait(callback, seconds) {
    var timelag = null;
    timelag = window.setTimeout(callback, seconds);
  }
  !function (e, t, a) {
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '<i class="ri-file-copy-2-line"></i><span>COPY</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      $(".article pre code").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });
      clipboard.on('success', function(e) {
        let $btn = $(e.trigger);
        $btn.addClass('copied');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-checkbox-circle-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPIED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-checkbox-circle-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
      clipboard.on('error', function(e) {
        e.clearSelection();
        let $btn = $(e.trigger);
        $btn.addClass('copy-failed');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-time-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPY FAILED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-time-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
    }
    initCopyCode();
  }(window, document);
</script>




    
  </div>
</body>

</html>